From 922d42d21de7706666dff1ca07ca40aa32541398 Mon Sep 17 00:00:00 2001 From: Nitzan Jaitman Date: Wed, 11 Nov 2020 09:48:43 +0200 Subject: [PATCH 001/150] Add support for variables in text style. (#225) --- .../cloudinary/transformation/TextLayer.java | 29 ++++++++++++++++++- .../com/cloudinary/test/CloudinaryTest.java | 24 +++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/cloudinary-core/src/main/java/com/cloudinary/transformation/TextLayer.java b/cloudinary-core/src/main/java/com/cloudinary/transformation/TextLayer.java index df2986c4..55380df3 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/transformation/TextLayer.java +++ b/cloudinary-core/src/main/java/com/cloudinary/transformation/TextLayer.java @@ -21,6 +21,7 @@ public class TextLayer extends AbstractLayer { protected String letterSpacing = null; protected Integer lineSpacing = null; protected String text = null; + protected Object textStyle = null; @Override TextLayer getThis() { @@ -118,6 +119,28 @@ public TextLayer text(String text) { return getThis(); } + /** + * Sets a text style identifier, + * Note: If this is used, all other style attributes are ignored in favor of this identifier + * @param textStyleIdentifier A variable string or an explicit style (e.g. "Arial_17_bold_antialias_best") + * @return Itself for chaining + */ + public TextLayer textStyle(String textStyleIdentifier) { + this.textStyle = textStyleIdentifier; + return getThis(); + } + + /** + * Sets a text style identifier using an expression. + * Note: If this is used, all other style attributes are ignored in favor of this identifier + * @param textStyleIdentifier An expression instance referencing the style. + * @return Itself for chaining + */ + public TextLayer textStyle(Expression textStyleIdentifier) { + this.textStyle = textStyleIdentifier; + return getThis(); + } + @Override public String toString() { if (this.publicId == null && this.text == null) { @@ -144,6 +167,11 @@ public String toString() { } protected String textStyleIdentifier() { + // Note: if a text-style argument is provided as a whole, it overrides everything else, no mix and match. + if (StringUtils.isNotBlank(this.textStyle)) { + return textStyle.toString(); + } + ArrayList components = new ArrayList(); if (StringUtils.isNotBlank(this.fontWeight) && !this.fontWeight.equals("normal")) @@ -181,6 +209,5 @@ protected String textStyleIdentifier() { components.add(0, this.fontFamily); return StringUtils.join(components, "_"); - } } diff --git a/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java b/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java index 7202e993..e0875980 100644 --- a/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java +++ b/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java @@ -101,6 +101,30 @@ public void testSecureDistribution() { assertEquals("https://res.cloudinary.com/test123/image/upload/test", result); } + @Test + public void testTextLayerStyleIdentifierVariables() { + String url = cloudinary.url().transformation( + new Transformation() + .variable("$style", "!Arial_12!") + .chain() + .overlay( + new TextLayer().text("hello-world").textStyle("$style") + )).generate("sample"); + + assertEquals("http://res.cloudinary.com/test123/image/upload/$style_!Arial_12!/l_text:$style:hello-world/sample", url); + + url = cloudinary.url().transformation( + new Transformation() + .variable("$style", "!Arial_12!") + .chain() + .overlay( + new TextLayer().text("hello-world").textStyle(new Expression("$style")) + )).generate("sample"); + + assertEquals("http://res.cloudinary.com/test123/image/upload/$style_!Arial_12!/l_text:$style:hello-world/sample", url); + } + + @Test public void testSecureDistributionOverwrite() { // should allow overwriting secure distribution if secure=TRUE From 7842e9a0320d670d23a4dabcc61187a2498aa2d1 Mon Sep 17 00:00:00 2001 From: Michal kuperman <51990104+michalkcloudinay@users.noreply.github.com> Date: Mon, 16 Nov 2020 09:51:44 +0200 Subject: [PATCH 002/150] Support `type` parameter in `Uploader.updateMetadata()` (#226) --- cloudinary-core/src/main/java/com/cloudinary/Uploader.java | 1 + .../com/cloudinary/test/AbstractStructuredMetadataTest.java | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/cloudinary-core/src/main/java/com/cloudinary/Uploader.java b/cloudinary-core/src/main/java/com/cloudinary/Uploader.java index c4ee5d59..65d74a0f 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Uploader.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Uploader.java @@ -532,6 +532,7 @@ public Map updateMetadata(Map metadata, String[] publicIds, Map options) throws Map params = new HashMap(); params.put("metadata", Util.encodeContext(metadata)); params.put("public_ids", Arrays.asList(publicIds)); + params.put("type", (String)options.get("type")); return callApi("metadata", params, options, null); } diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractStructuredMetadataTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractStructuredMetadataTest.java index 1256545b..e073e442 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractStructuredMetadataTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractStructuredMetadataTest.java @@ -18,6 +18,7 @@ public abstract class AbstractStructuredMetadataTest extends MockableTest { private static final String METADATA_UPLOADER_TAG = SDK_TEST_TAG + "_uploader"; private static final String PUBLIC_ID = "before_class_public_id" + SUFFIX; + private static final String PRIVATE_PUBLIC_ID = "before_class_private_public_id" + SUFFIX; protected Api api; public static final List metadataFieldExternalIds = new ArrayList(); @@ -29,6 +30,7 @@ public static void setUpClass() throws IOException { } cloudinary.uploader().upload(SRC_TEST_IMAGE, asMap("public_id", PUBLIC_ID)); + cloudinary.uploader().upload(SRC_TEST_IMAGE, asMap("public_id", PRIVATE_PUBLIC_ID, "type", "private")); } @AfterClass @@ -226,6 +228,10 @@ public void testUploaderUpdateMetadata() throws Exception { Map result = cloudinary.uploader().updateMetadata(Collections.singletonMap(fieldId, "123456"), new String[]{PUBLIC_ID}, null); assertNotNull(result); assertEquals(PUBLIC_ID, ((List) result.get("public_ids")).get(0).toString()); + //test updateMetadata for private asset + Map result2 = cloudinary.uploader().updateMetadata(Collections.singletonMap(fieldId, "123456"), new String[]{PRIVATE_PUBLIC_ID}, asMap("type","private")); + assertNotNull(result); + assertEquals(PRIVATE_PUBLIC_ID, ((List) result2.get("public_ids")).get(0).toString()); } @Test From 16f8e2118f379bfcb15a9b7feaf38b53166c2212 Mon Sep 17 00:00:00 2001 From: Nitzan Jaitman Date: Mon, 16 Nov 2020 20:43:39 +0200 Subject: [PATCH 003/150] Version 1.27.0 --- CHANGELOG.md | 22 +++++++++++++++++++ README.md | 4 ++-- .../main/java/com/cloudinary/Cloudinary.java | 2 +- gradle.properties | 2 +- 4 files changed, 26 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3bf063d2..8ad93a31 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,26 @@ +1.27.0 / 2020-11-16 +=================== + +New functionality +----------------- + * Support `type` parameter in `Uploader.updateMetadata()` (#226) + * Add `downloadFolder` method (#219) + * Add eval upload parameter (#217) + * Add support of SHA-256 algorithm in calculation of auth signatures (#215) + * Support different radius for each corner (#212) + * Add support for variables in text style. (#225) + * Add support for 'accessibility_analysis' parameter (#218) + * Support new parameter and modes in `generateSprite()` and `multi()` API cals. + * Add support for `date` param in `Api.usage()` (#210) + + +Other changes +------------- + * Fix named transformation with spaces (#224) + * Fix normalize_expression for complex cases (#216) + * Detect data URLs with suffix in mime type (#213) + 1.26.0 / 2020-05-05 =================== diff --git a/README.md b/README.md index 58079075..69ef18cf 100644 --- a/README.md +++ b/README.md @@ -34,11 +34,11 @@ The cloudinary_java library is available in [Maven Central](https://repo1.maven. com.cloudinary cloudinary-http44 - 1.26.0 + 1.27.0 ``` -Alternatively, download cloudinary_java from [here](https://repo1.maven.org/maven2/com/cloudinary/cloudinary-core/1.26.0/cloudinary-core-1.26.0.jar) and [here](https://repo1.maven.org/maven2/com/cloudinary/cloudinary-http44/1.26.0/cloudinary-http44-1.26.0.jar) +Alternatively, download cloudinary_java from [here](https://repo1.maven.org/maven2/com/cloudinary/cloudinary-core/1.27.0/cloudinary-core-1.27.0.jar) and [here](https://repo1.maven.org/maven2/com/cloudinary/cloudinary-http44/1.27.0/cloudinary-http44-1.27.0.jar) and see [build.gradle](https://github.com/cloudinary/cloudinary_java/blob/master/cloudinary-http44/build.gradle) for library dependencies. ## Try it right away diff --git a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java index 88cece6b..07ec04a0 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java @@ -35,7 +35,7 @@ public class Cloudinary { public final static String AKAMAI_SHARED_CDN = "res.cloudinary.com"; public final static String SHARED_CDN = AKAMAI_SHARED_CDN; - public final static String VERSION = "1.26.0"; + public final static String VERSION = "1.27.0"; public final static String USER_AGENT = "CloudinaryJava/" + VERSION + " (Java " + System.getProperty("java.version") + ")"; public final Configuration config; diff --git a/gradle.properties b/gradle.properties index bf43c39f..07263ab8 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,7 +13,7 @@ developerEmail=info@cloudinary.com # These two properties must use these exact names to be compatible with 'gradle install' plugin. group=com.cloudinary -version=1.26.0 +version=1.27.0 gnsp.disableApplyOnlyOnRootProjectEnforcement=true From 1ce6675ef248063f7a0879a6aa2020a8660ec572 Mon Sep 17 00:00:00 2001 From: Nitzan Jaitman Date: Tue, 19 Jan 2021 17:45:53 +0200 Subject: [PATCH 004/150] Add `oauth` support to Admin Api calls. (#230) Fix `timeout` config value on copy. --- .../java/com/cloudinary/Configuration.java | 20 ++++++++++++++++--- .../strategies/AbstractApiStrategy.java | 16 +++++++++++++++ .../com/cloudinary/http42/ApiStrategy.java | 13 ++++++------ .../com/cloudinary/http43/ApiStrategy.java | 6 +++--- .../com/cloudinary/http44/ApiStrategy.java | 8 ++++---- .../com/cloudinary/test/AbstractApiTest.java | 14 ++++++++++++- 6 files changed, 60 insertions(+), 17 deletions(-) diff --git a/cloudinary-core/src/main/java/com/cloudinary/Configuration.java b/cloudinary-core/src/main/java/com/cloudinary/Configuration.java index b21aa799..18e813ce 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Configuration.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Configuration.java @@ -47,6 +47,7 @@ public class Configuration { public boolean forceVersion = true; public boolean longUrlSignature = DEFAULT_IS_LONG_SIGNATURE; public SignatureAlgorithm signatureAlgorithm = DEFAULT_SIGNATURE_ALGORITHM; + public String oauthToken = null; public Configuration() { } @@ -71,7 +72,8 @@ private Configuration( boolean loadStrategies, boolean forceVersion, boolean longUrlSignature, - SignatureAlgorithm signatureAlgorithm) { + SignatureAlgorithm signatureAlgorithm, + String oauthToken) { this.cloudName = cloudName; this.apiKey = apiKey; this.apiSecret = apiSecret; @@ -87,11 +89,12 @@ private Configuration( this.proxyPort = proxyPort; this.secureCdnSubdomain = secureCdnSubdomain; this.useRootPath = useRootPath; - this.timeout = 0; + this.timeout = timeout; this.loadStrategies = loadStrategies; this.forceVersion = forceVersion; this.longUrlSignature = longUrlSignature; this.signatureAlgorithm = signatureAlgorithm; + this.oauthToken = oauthToken; } @SuppressWarnings("rawtypes") @@ -130,6 +133,7 @@ public void update(Map config) { } this.longUrlSignature = ObjectUtils.asBoolean(config.get("long_url_signature"), DEFAULT_IS_LONG_SIGNATURE); this.signatureAlgorithm = SignatureAlgorithm.valueOf(ObjectUtils.asString(config.get(CONFIG_PROP_SIGNATURE_ALGORITHM), DEFAULT_SIGNATURE_ALGORITHM.name())); + this.oauthToken = (String) config.get("oauth_token"); } @SuppressWarnings("rawtypes") @@ -160,6 +164,7 @@ public Map asMap() { map.put("properties", new HashMap(properties)); map.put("long_url_signature", longUrlSignature); map.put(CONFIG_PROP_SIGNATURE_ALGORITHM, signatureAlgorithm.toString()); + map.put("oauth_token", oauthToken); return map; } @@ -190,6 +195,7 @@ public Configuration(Configuration other) { this.properties.putAll(other.properties); this.longUrlSignature = other.longUrlSignature; this.signatureAlgorithm = other.signatureAlgorithm; + this.oauthToken = other.oauthToken; } /** @@ -301,6 +307,7 @@ public static class Builder { private boolean forceVersion = true; private boolean longUrlSignature = DEFAULT_IS_LONG_SIGNATURE; private SignatureAlgorithm signatureAlgorithm = DEFAULT_SIGNATURE_ALGORITHM; + private String oauthToken = null; /** * Set the HTTP connection timeout. @@ -337,7 +344,8 @@ public Configuration build() { loadStrategies, forceVersion, longUrlSignature, - signatureAlgorithm); + signatureAlgorithm, + oauthToken); configuration.clientHints = clientHints; return configuration; } @@ -466,6 +474,11 @@ public Builder setSignatureAlgorithm(SignatureAlgorithm signatureAlgorithm) { return this; } + public Builder setOAuthToken(String oauthToken) { + this.oauthToken = oauthToken; + return this; + } + /** * Initialize builder from existing {@link Configuration} * @@ -495,6 +508,7 @@ public Builder from(Configuration other) { this.forceVersion = other.forceVersion; this.longUrlSignature = other.longUrlSignature; this.signatureAlgorithm = other.signatureAlgorithm; + this.oauthToken = other.oauthToken; return this; } } diff --git a/cloudinary-core/src/main/java/com/cloudinary/strategies/AbstractApiStrategy.java b/cloudinary-core/src/main/java/com/cloudinary/strategies/AbstractApiStrategy.java index 65d0970d..9e427c4a 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/strategies/AbstractApiStrategy.java +++ b/cloudinary-core/src/main/java/com/cloudinary/strategies/AbstractApiStrategy.java @@ -4,6 +4,7 @@ import com.cloudinary.Api.HttpMethod; import com.cloudinary.SmartUrlEncoder; import com.cloudinary.api.ApiResponse; +import com.cloudinary.utils.Base64Coder; import com.cloudinary.utils.StringUtils; import java.util.Arrays; import java.util.Map; @@ -31,4 +32,19 @@ protected String createApiUrl (Iterable uri, String prefix, String cloud public abstract ApiResponse callApi(HttpMethod method, Iterable uri, Map params, Map options) throws Exception; public abstract ApiResponse callAccountApi(HttpMethod method, Iterable uri, Map params, Map options) throws Exception; + + protected String getAuthorizationHeaderValue(String apiKey, String apiSecret, String oauthToken) { + if (oauthToken != null){ + return "Bearer " + oauthToken; + } else { + return "Basic " + Base64Coder.encodeString(apiKey + ":" + apiSecret); + } + } + + protected void validateAuthorization(String apiKey, String apiSecret, String oauthToken) { + if (oauthToken == null) { + if (apiKey == null) throw new IllegalArgumentException("Must supply api_key"); + if (apiSecret == null) throw new IllegalArgumentException("Must supply api_secret"); + } + } } diff --git a/cloudinary-http42/src/main/java/com/cloudinary/http42/ApiStrategy.java b/cloudinary-http42/src/main/java/com/cloudinary/http42/ApiStrategy.java index 7c19aeb9..a8aa7c93 100644 --- a/cloudinary-http42/src/main/java/com/cloudinary/http42/ApiStrategy.java +++ b/cloudinary-http42/src/main/java/com/cloudinary/http42/ApiStrategy.java @@ -38,14 +38,15 @@ public ApiResponse callApi(HttpMethod method, Iterable uri, Map uri, Map params, String apiKey, String apiSecret, String contentType, int timeout, String apiUrl) throws Exception { + private ApiResponse getApiResponse(HttpMethod method, Map params, String apiKey, String apiSecret, String oauthToken, String contentType, int timeout, String apiUrl) throws Exception { URIBuilder apiUrlBuilder = new URIBuilder(apiUrl); if (!contentType.equals("json")) { for (Map.Entry param : params.entrySet()) { @@ -105,7 +106,7 @@ private ApiResponse getApiResponse(HttpMethod method, Map params, Str request = new HttpDelete(apiUri); break; } - request.setHeader("Authorization", "Basic " + Base64Coder.encodeString(apiKey + ":" + apiSecret)); + request.setHeader("Authorization", getAuthorizationHeaderValue(apiKey, apiSecret, oauthToken)); request.setHeader("User-Agent", Cloudinary.USER_AGENT + " ApacheHTTPComponents/4.2"); if (contentType.equals("json")) { JSONObject asJSON = ObjectUtils.toJSON(params); diff --git a/cloudinary-http43/src/main/java/com/cloudinary/http43/ApiStrategy.java b/cloudinary-http43/src/main/java/com/cloudinary/http43/ApiStrategy.java index 400e252d..1d1b4232 100644 --- a/cloudinary-http43/src/main/java/com/cloudinary/http43/ApiStrategy.java +++ b/cloudinary-http43/src/main/java/com/cloudinary/http43/ApiStrategy.java @@ -79,15 +79,15 @@ public ApiResponse callApi(HttpMethod method, Iterable uri, Map uri, Map uri, Map 0); } + @Test + public void testOAuthToken() { + String message = ""; + try { + api.resource(API_TEST, Collections.singletonMap("oauth_token", "not_a_real_token")); + } catch (Exception e) { + message = e.getMessage(); + } + + assertTrue(message.contains("Invalid token")); + } + @Test public void test05ResourcesByPrefix() throws Exception { // should allow listing resources by prefix @@ -996,7 +1008,7 @@ public void testCinemagraphAnalysisResource() throws Exception { ApiResponse res = api.resource(API_TEST, Collections.singletonMap("cinemagraph_analysis", true)); assertNotNull(res.get("cinemagraph_analysis")); } - + @Test public void testAccessibilityAnalysisResource() throws Exception { ApiResponse res = api.resource(API_TEST, Collections.singletonMap("accessibility_analysis", true)); From a4679346f235dfb87ef5ee68e33fa98f6d4033a0 Mon Sep 17 00:00:00 2001 From: Nitzan Jaitman Date: Sun, 31 Jan 2021 17:55:20 +0200 Subject: [PATCH 005/150] Fix connection reuse when using apache-http-client versions 4.3 and 4.4 (#231) --- .../src/main/java/com/cloudinary/http43/ApiStrategy.java | 7 +++++-- .../src/main/java/com/cloudinary/http44/ApiStrategy.java | 7 +++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/cloudinary-http43/src/main/java/com/cloudinary/http43/ApiStrategy.java b/cloudinary-http43/src/main/java/com/cloudinary/http43/ApiStrategy.java index 1d1b4232..ef02ce17 100644 --- a/cloudinary-http43/src/main/java/com/cloudinary/http43/ApiStrategy.java +++ b/cloudinary-http43/src/main/java/com/cloudinary/http43/ApiStrategy.java @@ -10,6 +10,7 @@ import com.cloudinary.utils.ObjectUtils; import com.cloudinary.utils.StringUtils; import org.apache.http.Consts; +import org.apache.http.HttpEntity; import org.apache.http.HttpHost; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.entity.UrlEncodedFormEntity; @@ -21,6 +22,7 @@ import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.client.HttpClients; +import org.apache.http.util.EntityUtils; import org.cloudinary.json.JSONException; import org.cloudinary.json.JSONObject; @@ -98,8 +100,9 @@ private ApiResponse getApiResponse(HttpUriRequest request) throws Exception { CloseableHttpResponse response = client.execute(request); try { code = response.getStatusLine().getStatusCode(); - InputStream responseStream = response.getEntity().getContent(); - responseData = StringUtils.read(responseStream); + final HttpEntity entity = response.getEntity(); + responseData = StringUtils.read(entity.getContent()); + EntityUtils.consume(entity); } finally { response.close(); } diff --git a/cloudinary-http44/src/main/java/com/cloudinary/http44/ApiStrategy.java b/cloudinary-http44/src/main/java/com/cloudinary/http44/ApiStrategy.java index bfe67f59..df8eedb3 100644 --- a/cloudinary-http44/src/main/java/com/cloudinary/http44/ApiStrategy.java +++ b/cloudinary-http44/src/main/java/com/cloudinary/http44/ApiStrategy.java @@ -10,6 +10,7 @@ import com.cloudinary.utils.ObjectUtils; import com.cloudinary.utils.StringUtils; import org.apache.http.Consts; +import org.apache.http.HttpEntity; import org.apache.http.HttpHost; import org.apache.http.NameValuePair; import org.apache.http.client.config.RequestConfig; @@ -22,6 +23,7 @@ import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.client.HttpClients; +import org.apache.http.util.EntityUtils; import org.cloudinary.json.JSONException; import org.cloudinary.json.JSONObject; @@ -100,8 +102,9 @@ private ApiResponse getApiResponse(HttpUriRequest request) throws Exception { CloseableHttpResponse response = client.execute(request); try { code = response.getStatusLine().getStatusCode(); - InputStream responseStream = response.getEntity().getContent(); - responseData = StringUtils.read(responseStream); + final HttpEntity entity = response.getEntity(); + responseData = StringUtils.read(entity.getContent()); + EntityUtils.consume(entity); } finally { response.close(); } From 4cb77620de288eac09d529bd92c3464fabdf0ff1 Mon Sep 17 00:00:00 2001 From: Nitzan Jaitman Date: Mon, 1 Feb 2021 19:23:41 +0200 Subject: [PATCH 006/150] Version 1.28.0 --- CHANGELOG.md | 6 ++++++ README.md | 4 ++-- .../src/main/java/com/cloudinary/Cloudinary.java | 2 +- gradle.properties | 2 +- 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ad93a31..d2f1f294 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,10 @@ +1.28.0 / 2021-02-01 +================== + + * Add `oauth` support to Admin Api calls. (#230) + * Fix connection reuse when using apache-http-client (versions 4.3 and 4.4) (#231) + 1.27.0 / 2020-11-16 =================== diff --git a/README.md b/README.md index 69ef18cf..216bd90d 100644 --- a/README.md +++ b/README.md @@ -34,11 +34,11 @@ The cloudinary_java library is available in [Maven Central](https://repo1.maven. com.cloudinary cloudinary-http44 - 1.27.0 + 1.28.0 ``` -Alternatively, download cloudinary_java from [here](https://repo1.maven.org/maven2/com/cloudinary/cloudinary-core/1.27.0/cloudinary-core-1.27.0.jar) and [here](https://repo1.maven.org/maven2/com/cloudinary/cloudinary-http44/1.27.0/cloudinary-http44-1.27.0.jar) +Alternatively, download cloudinary_java from [here](https://repo1.maven.org/maven2/com/cloudinary/cloudinary-core/1.28.0/cloudinary-core-1.28.0.jar) and [here](https://repo1.maven.org/maven2/com/cloudinary/cloudinary-http44/1.28.0/cloudinary-http44-1.28.0.jar) and see [build.gradle](https://github.com/cloudinary/cloudinary_java/blob/master/cloudinary-http44/build.gradle) for library dependencies. ## Try it right away diff --git a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java index 07ec04a0..1f2a05a0 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java @@ -35,7 +35,7 @@ public class Cloudinary { public final static String AKAMAI_SHARED_CDN = "res.cloudinary.com"; public final static String SHARED_CDN = AKAMAI_SHARED_CDN; - public final static String VERSION = "1.27.0"; + public final static String VERSION = "1.28.0"; public final static String USER_AGENT = "CloudinaryJava/" + VERSION + " (Java " + System.getProperty("java.version") + ")"; public final Configuration config; diff --git a/gradle.properties b/gradle.properties index 07263ab8..751b66a8 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,7 +13,7 @@ developerEmail=info@cloudinary.com # These two properties must use these exact names to be compatible with 'gradle install' plugin. group=com.cloudinary -version=1.27.0 +version=1.28.0 gnsp.disableApplyOnlyOnRootProjectEnforcement=true From 3602cc7b57f68ff5eac47fc55b2a9e32972466cf Mon Sep 17 00:00:00 2001 From: Nitzan Jaitman Date: Wed, 3 Feb 2021 07:51:13 +0200 Subject: [PATCH 007/150] Fix `api` reuse bug when calling `cloudinary.search()` (#232) --- cloudinary-core/src/main/java/com/cloudinary/Search.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cloudinary-core/src/main/java/com/cloudinary/Search.java b/cloudinary-core/src/main/java/com/cloudinary/Search.java index 94cd222a..dc2f8a96 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Search.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Search.java @@ -10,14 +10,14 @@ public class Search { - private Cloudinary cloudinary; + private final Api api; private ArrayList> sortByParam; private ArrayList aggregateParam; private ArrayList withFieldParam; private HashMap params; Search(Cloudinary cloudinary) { - this.cloudinary = cloudinary; + this.api = cloudinary.api(); this.params = new HashMap(); this.sortByParam = new ArrayList>(); this.aggregateParam = new ArrayList(); @@ -66,6 +66,6 @@ public HashMap toQuery() { public ApiResponse execute() throws Exception { Map options = ObjectUtils.asMap("content_type", "json"); - return this.cloudinary.api().callApi(Api.HttpMethod.POST, Arrays.asList("resources", "search"), this.toQuery(), options); + return this.api.callApi(Api.HttpMethod.POST, Arrays.asList("resources", "search"), this.toQuery(), options); } } \ No newline at end of file From 0ae1065b691f25f406b197a549cbaafe103b44c7 Mon Sep 17 00:00:00 2001 From: Nitzan Jaitman Date: Wed, 3 Feb 2021 07:59:01 +0200 Subject: [PATCH 008/150] Version 1.28.1 --- CHANGELOG.md | 7 ++++++- README.md | 4 ++-- .../src/main/java/com/cloudinary/Cloudinary.java | 2 +- gradle.properties | 2 +- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d2f1f294..c5cfd8dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ -1.28.0 / 2021-02-01 +1.28.1 / 2021-02-03 +================== + + * Fix `api` reuse bug when calling `cloudinary.search()` (#232) + +1.28.1 / 2021-02-01 ================== * Add `oauth` support to Admin Api calls. (#230) diff --git a/README.md b/README.md index 216bd90d..a9d61ce0 100644 --- a/README.md +++ b/README.md @@ -34,11 +34,11 @@ The cloudinary_java library is available in [Maven Central](https://repo1.maven. com.cloudinary cloudinary-http44 - 1.28.0 + 1.28.1 ``` -Alternatively, download cloudinary_java from [here](https://repo1.maven.org/maven2/com/cloudinary/cloudinary-core/1.28.0/cloudinary-core-1.28.0.jar) and [here](https://repo1.maven.org/maven2/com/cloudinary/cloudinary-http44/1.28.0/cloudinary-http44-1.28.0.jar) +Alternatively, download cloudinary_java from [here](https://repo1.maven.org/maven2/com/cloudinary/cloudinary-core/1.28.1/cloudinary-core-1.28.1.jar) and [here](https://repo1.maven.org/maven2/com/cloudinary/cloudinary-http44/1.28.1/cloudinary-http44-1.28.1.jar) and see [build.gradle](https://github.com/cloudinary/cloudinary_java/blob/master/cloudinary-http44/build.gradle) for library dependencies. ## Try it right away diff --git a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java index 1f2a05a0..1ed4521b 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java @@ -35,7 +35,7 @@ public class Cloudinary { public final static String AKAMAI_SHARED_CDN = "res.cloudinary.com"; public final static String SHARED_CDN = AKAMAI_SHARED_CDN; - public final static String VERSION = "1.28.0"; + public final static String VERSION = "1.28.1"; public final static String USER_AGENT = "CloudinaryJava/" + VERSION + " (Java " + System.getProperty("java.version") + ")"; public final Configuration config; diff --git a/gradle.properties b/gradle.properties index 751b66a8..484fccbd 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,7 +13,7 @@ developerEmail=info@cloudinary.com # These two properties must use these exact names to be compatible with 'gradle install' plugin. group=com.cloudinary -version=1.28.0 +version=1.28.1 gnsp.disableApplyOnlyOnRootProjectEnforcement=true From ae2434294b880f9e552f26d2a049c27c7f900dfe Mon Sep 17 00:00:00 2001 From: RTLcoil Date: Thu, 4 Feb 2021 18:05:08 +0200 Subject: [PATCH 009/150] Fix test name in `ExpressionTest` (#233) --- .../java/com/cloudinary/transformation/ExpressionTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cloudinary-core/src/test/java/com/cloudinary/transformation/ExpressionTest.java b/cloudinary-core/src/test/java/com/cloudinary/transformation/ExpressionTest.java index 733f1a2a..69615769 100644 --- a/cloudinary-core/src/test/java/com/cloudinary/transformation/ExpressionTest.java +++ b/cloudinary-core/src/test/java/com/cloudinary/transformation/ExpressionTest.java @@ -80,7 +80,7 @@ public void normalize_width_recognizedAsVariableAndReplacedWithW() { } @Test - public void normalize_initialAspectRatio_recognizedAsVariableAndReplacedWithW() { + public void normalize_initialAspectRatio_recognizedAsVariableAndReplacedWithIar() { String result = Expression.normalize("initial_aspect_ratio"); assertEquals("iar", result); } @@ -174,4 +174,4 @@ public void normalize_doesntReplaceVariable_8() { String actual = Expression.normalize("$__height_100"); assertEquals("$_height_100", actual); } -} \ No newline at end of file +} From f66644b90036ae8225bba70a0e63728057d6003f Mon Sep 17 00:00:00 2001 From: Nitzan Jaitman Date: Tue, 9 Feb 2021 18:27:39 +0200 Subject: [PATCH 010/150] Add support for apache http-client 4.5 (#234) --- .travis.yml | 1 + .../main/java/com/cloudinary/Cloudinary.java | 6 +- cloudinary-http45/build.gradle | 120 ++++++++++ .../com/cloudinary/http45/ApiStrategy.java | 205 ++++++++++++++++++ .../java/com/cloudinary/http45/ApiUtils.java | 53 +++++ .../cloudinary/http45/UploaderStrategy.java | 139 ++++++++++++ .../com/cloudinary/http45/api/Response.java | 69 ++++++ .../com/cloudinary/test/AccountApiTest.java | 4 + .../java/com/cloudinary/test/ApiTest.java | 32 +++ .../java/com/cloudinary/test/ContextTest.java | 5 + .../com/cloudinary/test/FoldersApiTest.java | 4 + .../java/com/cloudinary/test/SearchTest.java | 4 + .../test/StreamingProfilesApiTest.java | 4 + .../test/StructuredMetadataTest.java | 4 + .../com/cloudinary/test/UploaderTest.java | 34 +++ settings.gradle | 1 + 16 files changed, 683 insertions(+), 2 deletions(-) create mode 100644 cloudinary-http45/build.gradle create mode 100644 cloudinary-http45/src/main/java/com/cloudinary/http45/ApiStrategy.java create mode 100644 cloudinary-http45/src/main/java/com/cloudinary/http45/ApiUtils.java create mode 100644 cloudinary-http45/src/main/java/com/cloudinary/http45/UploaderStrategy.java create mode 100644 cloudinary-http45/src/main/java/com/cloudinary/http45/api/Response.java create mode 100644 cloudinary-http45/src/test/java/com/cloudinary/test/AccountApiTest.java create mode 100644 cloudinary-http45/src/test/java/com/cloudinary/test/ApiTest.java create mode 100644 cloudinary-http45/src/test/java/com/cloudinary/test/ContextTest.java create mode 100644 cloudinary-http45/src/test/java/com/cloudinary/test/FoldersApiTest.java create mode 100644 cloudinary-http45/src/test/java/com/cloudinary/test/SearchTest.java create mode 100644 cloudinary-http45/src/test/java/com/cloudinary/test/StreamingProfilesApiTest.java create mode 100644 cloudinary-http45/src/test/java/com/cloudinary/test/StructuredMetadataTest.java create mode 100644 cloudinary-http45/src/test/java/com/cloudinary/test/UploaderTest.java diff --git a/.travis.yml b/.travis.yml index 72169c8a..d71e7b1e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,6 +21,7 @@ env: - MODULE=http42 - MODULE=http43 - MODULE=http44 + - MODULE=http45 branches: except: diff --git a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java index 1ed4521b..1cf44999 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java @@ -23,12 +23,14 @@ public class Cloudinary { "com.cloudinary.android.UploaderStrategy", "com.cloudinary.http42.UploaderStrategy", "com.cloudinary.http43.UploaderStrategy", - "com.cloudinary.http44.UploaderStrategy")); + "com.cloudinary.http44.UploaderStrategy", + "com.cloudinary.http45.UploaderStrategy")); public static List API_STRATEGIES = new ArrayList(Arrays.asList( "com.cloudinary.android.ApiStrategy", "com.cloudinary.http42.ApiStrategy", "com.cloudinary.http43.ApiStrategy", - "com.cloudinary.http44.ApiStrategy")); + "com.cloudinary.http44.ApiStrategy", + "com.cloudinary.http45.ApiStrategy")); public final static String CF_SHARED_CDN = "d3jpl91pxevbkh.cloudfront.net"; public final static String OLD_AKAMAI_SHARED_CDN = "cloudinary-a.akamaihd.net"; diff --git a/cloudinary-http45/build.gradle b/cloudinary-http45/build.gradle new file mode 100644 index 00000000..13be8f83 --- /dev/null +++ b/cloudinary-http45/build.gradle @@ -0,0 +1,120 @@ +plugins { + id 'java-library' + id 'signing' + id 'maven-publish' + id 'io.codearte.nexus-staging' version '0.21.1' + id "de.marcphilipp.nexus-publish" version "0.4.0" +} + +apply from: "../java_shared.gradle" + +task ciTest( type: Test ) { + useJUnit { + excludeCategories 'com.cloudinary.test.TimeoutTest' + } +} + +dependencies { + compile project(':cloudinary-core') + compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.1' + compile group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.5.13' + compile group: 'org.apache.httpcomponents', name: 'httpmime', version: '4.5.13' + testCompile project(':cloudinary-test-common') + testCompile group: 'org.hamcrest', name: 'java-hamcrest', version: '2.0.0.0' + testCompile group: 'pl.pragmatists', name: 'JUnitParams', version: '1.0.5' + testCompile group: 'junit', name: 'junit', version: '4.12' +} + +if (hasProperty("ossrhPassword")) { + + signing { + sign configurations.archives + } + + nexusStaging { + packageGroup = group + username = project.hasProperty("ossrhUsername") ? project.ext["ossrhUsername"] : "" + password = project.hasProperty("ossrhPassword") ? project.ext["ossrhPassword"] : "" + } + + publishing { + publications { + mavenJava(MavenPublication) { + from components.java + artifact sourcesJar + artifact javadocJar + pom { + name = 'Cloudinary Apache HTTP 4.5 Library' + packaging = 'jar' + groupId = publishGroupId + artifactId = 'cloudinary-http45' + description = publishDescription + url = githubUrl + licenses { + license { + name = licenseName + url = licenseUrl + } + } + + developers { + developer { + id = developerId + name = developerName + email = developerEmail + } + } + scm { + connection = scmConnection + developerConnection = scmDeveloperConnection + url = scmUrl + } + } + + pom.withXml { + def pomFile = file("${project.buildDir}/generated-pom.xml") + writeTo(pomFile) + def pomAscFile = signing.sign(pomFile).signatureFiles[0] + artifact(pomAscFile) { + classifier = null + extension = 'pom.asc' + } + } + + // create the signed artifacts + project.tasks.signArchives.signatureFiles.each { + artifact(it) { + def matcher = it.file =~ /-(sources|javadoc)\.jar\.asc$/ + if (matcher.find()) { + classifier = matcher.group(1) + } else { + classifier = null + } + extension = 'jar.asc' + } + } + } + } + + nexusPublishing { + repositories { + sonatype { + username = project.hasProperty("ossrhUsername") ? project.ext["ossrhUsername"] : "" + password = project.hasProperty("ossrhPassword") ? project.ext["ossrhPassword"] : "" + } + } + } + + model { + tasks.generatePomFileForMavenJavaPublication { + destination = file("$buildDir/generated-pom.xml") + } + tasks.publishMavenJavaPublicationToMavenLocal { + dependsOn project.tasks.signArchives + } + tasks.publishMavenJavaPublicationToSonatypeRepository { + dependsOn project.tasks.signArchives + } + } + } +} \ No newline at end of file diff --git a/cloudinary-http45/src/main/java/com/cloudinary/http45/ApiStrategy.java b/cloudinary-http45/src/main/java/com/cloudinary/http45/ApiStrategy.java new file mode 100644 index 00000000..e7c55bf8 --- /dev/null +++ b/cloudinary-http45/src/main/java/com/cloudinary/http45/ApiStrategy.java @@ -0,0 +1,205 @@ +package com.cloudinary.http45; + +import com.cloudinary.Api; +import com.cloudinary.Api.HttpMethod; +import com.cloudinary.Cloudinary; +import com.cloudinary.api.ApiResponse; +import com.cloudinary.api.exceptions.GeneralError; +import com.cloudinary.http45.api.Response; +import com.cloudinary.utils.Base64Coder; +import com.cloudinary.utils.ObjectUtils; +import com.cloudinary.utils.StringUtils; +import org.apache.http.Consts; +import org.apache.http.HttpHost; +import org.apache.http.NameValuePair; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.*; +import org.apache.http.client.utils.URIBuilder; +import org.apache.http.conn.HttpClientConnectionManager; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.client.HttpClients; +import org.cloudinary.json.JSONException; +import org.cloudinary.json.JSONObject; + +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.lang.reflect.Constructor; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static com.cloudinary.http45.ApiUtils.prepareParams; +import static com.cloudinary.http45.ApiUtils.setTimeouts; + +public class ApiStrategy extends com.cloudinary.strategies.AbstractApiStrategy { + + private CloseableHttpClient client = null; + + @Override + public void init(Api api) { + super.init(api); + + HttpClientBuilder clientBuilder = HttpClients.custom(); + clientBuilder.useSystemProperties().setUserAgent(Cloudinary.USER_AGENT + " ApacheHTTPComponents/4.5"); + + // If the configuration specifies a proxy then apply it to the client + if (api.cloudinary.config.proxyHost != null && api.cloudinary.config.proxyPort != 0) { + HttpHost proxy = new HttpHost(api.cloudinary.config.proxyHost, api.cloudinary.config.proxyPort); + clientBuilder.setProxy(proxy); + } + + HttpClientConnectionManager connectionManager = (HttpClientConnectionManager) api.cloudinary.config.properties.get("connectionManager"); + if (connectionManager != null) { + clientBuilder.setConnectionManager(connectionManager); + } + + int timeout = this.api.cloudinary.config.timeout; + if (timeout > 0) { + RequestConfig config = RequestConfig.custom() + .setSocketTimeout(timeout * 1000) + .setConnectTimeout(timeout * 1000) + .build(); + clientBuilder.setDefaultRequestConfig(config); + } + + this.client = clientBuilder.build(); + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + public ApiResponse callApi(HttpMethod method, Iterable uri, Map params, Map options) throws Exception { + if (options == null) + options = ObjectUtils.emptyMap(); + + String prefix = ObjectUtils.asString(options.get("upload_prefix"), ObjectUtils.asString(this.api.cloudinary.config.uploadPrefix, "https://api.cloudinary.com")); + String cloudName = ObjectUtils.asString(options.get("cloud_name"), this.api.cloudinary.config.cloudName); + if (cloudName == null) throw new IllegalArgumentException("Must supply cloud_name"); + String apiKey = ObjectUtils.asString(options.get("api_key"), this.api.cloudinary.config.apiKey); + String apiSecret = ObjectUtils.asString(options.get("api_secret"), this.api.cloudinary.config.apiSecret); + String oauthToken = ObjectUtils.asString(options.get("oauth_token"), this.api.cloudinary.config.oauthToken); + + validateAuthorization(apiKey, apiSecret, oauthToken); + + + String apiUrl = createApiUrl(uri, prefix, cloudName); + HttpUriRequest request = prepareRequest(method, apiUrl, params, options); + + request.setHeader("Authorization", getAuthorizationHeaderValue(apiKey, apiSecret, oauthToken)); + + return getApiResponse(request); + } + + private ApiResponse getApiResponse(HttpUriRequest request) throws Exception { + String responseData = null; + int code = 0; + CloseableHttpResponse response = client.execute(request); + try { + code = response.getStatusLine().getStatusCode(); + InputStream responseStream = response.getEntity().getContent(); + responseData = StringUtils.read(responseStream); + } finally { + response.close(); + } + + Class exceptionClass = Api.CLOUDINARY_API_ERROR_CLASSES.get(code); + if (code != 200 && exceptionClass == null) { + throw new GeneralError("Server returned unexpected status code - " + code + " - " + responseData); + } + Map result; + + try { + JSONObject responseJSON = new JSONObject(responseData); + result = ObjectUtils.toMap(responseJSON); + } catch (JSONException e) { + throw new RuntimeException("Invalid JSON response from server " + e.getMessage()); + } + + if (code == 200) { + return new Response(response, result); + } else { + String message = (String) ((Map) result.get("error")).get("message"); + Constructor exceptionConstructor = exceptionClass.getConstructor(String.class); + throw exceptionConstructor.newInstance(message); + } + } + + @Override + public ApiResponse callAccountApi(HttpMethod method, Iterable uri, Map params, Map options) throws Exception { + if (options == null) + options = ObjectUtils.emptyMap(); + + String prefix = ObjectUtils.asString(options.get("upload_prefix"), "https://api.cloudinary.com"); + String apiKey = ObjectUtils.asString(options.get("provisioning_api_key")); + if (apiKey == null) throw new IllegalArgumentException("Must supply provisioning_api_key"); + String apiSecret = ObjectUtils.asString(options.get("provisioning_api_secret")); + if (apiSecret == null) throw new IllegalArgumentException("Must supply provisioning_api_secret"); + + String apiUrl = StringUtils.join(Arrays.asList(prefix, "v1_1"), "/"); + for (String component : uri) { + apiUrl = apiUrl + "/" + component; + } + + HttpUriRequest request = prepareRequest(method, apiUrl, params, options); + + request.setHeader("Authorization", getAuthorizationHeaderValue(apiKey, apiSecret, null)); + + return getApiResponse(request); + } + + /** + * Prepare a request with the URL and parameters based on the HTTP method used + * + * @param method the HTTP method: GET, PUT, POST, DELETE + * @param apiUrl the cloudinary API URI + * @param params the parameters to pass to the server + * @return an HTTP request + * @throws URISyntaxException + * @throws UnsupportedEncodingException + */ + private HttpUriRequest prepareRequest(HttpMethod method, String apiUrl, Map params, Map options) throws URISyntaxException, UnsupportedEncodingException { + URI apiUri; + HttpRequestBase request; + + String contentType = ObjectUtils.asString(options.get("content_type"), "urlencoded"); + URIBuilder apiUrlBuilder = new URIBuilder(apiUrl); + List urlEncodedParams = prepareParams(params); + + if (method == HttpMethod.GET) { + apiUrlBuilder.setParameters(prepareParams(params)); + apiUri = apiUrlBuilder.build(); + request = new HttpGet(apiUri); + } else { + Map paramsCopy = new HashMap((Map) params); + apiUri = apiUrlBuilder.build(); + switch (method) { + case PUT: + request = new HttpPut(apiUri); + break; + case DELETE: //uses HttpPost instead of HttpDelete + paramsCopy.put("_method", "delete"); + //continue with POST + case POST: + request = new HttpPost(apiUri); + break; + default: + throw new IllegalArgumentException("Unknown HTTP method"); + } + if (contentType.equals("json")) { + JSONObject asJSON = ObjectUtils.toJSON(paramsCopy); + StringEntity requestEntity = new StringEntity(asJSON.toString(), ContentType.APPLICATION_JSON); + ((HttpEntityEnclosingRequestBase) request).setEntity(requestEntity); + } else { + ((HttpEntityEnclosingRequestBase) request).setEntity(new UrlEncodedFormEntity(prepareParams(paramsCopy), Consts.UTF_8)); + } + } + + setTimeouts(request, options); + return request; + } +} diff --git a/cloudinary-http45/src/main/java/com/cloudinary/http45/ApiUtils.java b/cloudinary-http45/src/main/java/com/cloudinary/http45/ApiUtils.java new file mode 100644 index 00000000..6639b9cc --- /dev/null +++ b/cloudinary-http45/src/main/java/com/cloudinary/http45/ApiUtils.java @@ -0,0 +1,53 @@ +package com.cloudinary.http45; + +import com.cloudinary.utils.ObjectUtils; +import org.apache.http.NameValuePair; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.HttpRequestBase; +import org.apache.http.message.BasicNameValuePair; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class ApiUtils { + + public static void setTimeouts(HttpRequestBase request, Map options) { + RequestConfig config= request.getConfig(); + final RequestConfig.Builder builder; + if (config != null) { + builder = RequestConfig.copy(config); + } else { + builder = RequestConfig.custom(); + } + Integer timeout = (Integer) options.get("timeout"); + if(timeout != null) { + builder.setSocketTimeout(timeout); + } + Integer connectionRequestTimeout = (Integer) options.get("connection_request_timeout"); + if(connectionRequestTimeout != null) { + builder.setConnectionRequestTimeout(connectionRequestTimeout); + } + Integer connectTimeout = (Integer) options.get("connect_timeout"); + if(connectTimeout != null) { + builder.setConnectTimeout(connectTimeout); + } + request.setConfig(builder.build()); + } + + static List prepareParams(Map params) { + List requestParams = new ArrayList(params.size()); + for (Map.Entry param : params.entrySet()) { + if (param.getValue() instanceof Iterable) { + for (Object single : (Iterable) param.getValue()) { + requestParams.add(new BasicNameValuePair(param.getKey() + "[]", ObjectUtils.asString(single))); + } + } else { + requestParams.add(new BasicNameValuePair(param.getKey(), ObjectUtils.asString(param.getValue()))); + } + } + + + return requestParams; + } +} diff --git a/cloudinary-http45/src/main/java/com/cloudinary/http45/UploaderStrategy.java b/cloudinary-http45/src/main/java/com/cloudinary/http45/UploaderStrategy.java new file mode 100644 index 00000000..e29b07ad --- /dev/null +++ b/cloudinary-http45/src/main/java/com/cloudinary/http45/UploaderStrategy.java @@ -0,0 +1,139 @@ +package com.cloudinary.http45; + +import com.cloudinary.Cloudinary; +import com.cloudinary.ProgressCallback; +import com.cloudinary.Uploader; +import com.cloudinary.Util; +import com.cloudinary.strategies.AbstractUploaderStrategy; +import com.cloudinary.utils.ObjectUtils; +import com.cloudinary.utils.StringUtils; +import org.apache.http.HttpHost; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.conn.HttpClientConnectionManager; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.mime.HttpMultipartMode; +import org.apache.http.entity.mime.MIME; +import org.apache.http.entity.mime.MultipartEntityBuilder; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.client.HttpClients; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.Collection; +import java.util.Map; + +public class UploaderStrategy extends AbstractUploaderStrategy { + + private CloseableHttpClient client = null; + + @Override + public void init(Uploader uploader) { + super.init(uploader); + + HttpClientBuilder clientBuilder = HttpClients.custom(); + clientBuilder.useSystemProperties().setUserAgent(Cloudinary.USER_AGENT + " ApacheHTTPComponents/4.5"); + + // If the configuration specifies a proxy then apply it to the client + if (cloudinary().config.proxyHost != null && cloudinary().config.proxyPort != 0) { + HttpHost proxy = new HttpHost(cloudinary().config.proxyHost, cloudinary().config.proxyPort); + clientBuilder.setProxy(proxy); + } + + HttpClientConnectionManager connectionManager = (HttpClientConnectionManager) cloudinary().config.properties.get("connectionManager"); + if (connectionManager != null) { + clientBuilder.setConnectionManager(connectionManager); + } + + this.client = clientBuilder.build(); + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + @Override + public Map callApi(String action, Map params, Map options, Object file, ProgressCallback progressCallback) throws IOException { + if (progressCallback != null){ + throw new IllegalArgumentException("Progress callback is not supported"); + } + + // initialize options if passed as null + if (options == null) { + options = ObjectUtils.emptyMap(); + } + + boolean returnError = ObjectUtils.asBoolean(options.get("return_error"), false); + + if (requiresSigning(action, options)) { + uploader.signRequestParams(params, options); + } else { + Util.clearEmpty(params); + } + + String apiUrl = buildUploadUrl(action, options); + + HttpPost postMethod = new HttpPost(apiUrl); + ApiUtils.setTimeouts(postMethod, options); + + Map extraHeaders = (Map) options.get("extra_headers"); + if (extraHeaders != null) { + for (Map.Entry header : extraHeaders.entrySet()) { + postMethod.setHeader(header.getKey(), header.getValue()); + } + } + + MultipartEntityBuilder multipart = MultipartEntityBuilder.create(); + multipart.setMode(HttpMultipartMode.BROWSER_COMPATIBLE); + ContentType contentType = ContentType.MULTIPART_FORM_DATA.withCharset(MIME.UTF8_CHARSET); + // Remove blank parameters + for (Map.Entry param : params.entrySet()) { + if (param.getValue() instanceof Collection) { + for (Object value : (Collection) param.getValue()) { + multipart.addTextBody(param.getKey() + "[]", ObjectUtils.asString(value), contentType); + } + } else { + String value = param.getValue().toString(); + if (StringUtils.isNotBlank(value)) { + multipart.addTextBody(param.getKey(), value, contentType); + } + } + } + + if (file instanceof String && !StringUtils.isRemoteUrl((String) file)) { + File _file = new File((String) file); + if (!_file.isFile() && !_file.canRead()) { + throw new IOException("File not found or unreadable: " + file); + } + file = _file; + } + String filename = (String) options.get("filename"); + if (file instanceof File) { + if (filename == null) filename = ((File) file).getName(); + multipart.addBinaryBody("file", (File) file, ContentType.APPLICATION_OCTET_STREAM, filename); + } else if (file instanceof String) { + multipart.addTextBody("file", (String) file, contentType); + } else if (file instanceof byte[]) { + if (filename == null) filename = "file"; + multipart.addBinaryBody("file", (byte[]) file, ContentType.APPLICATION_OCTET_STREAM, filename); + } else if (file == null) { + // no-problem + } else { + throw new IOException("Unrecognized file parameter " + file); + } + postMethod.setEntity(multipart.build()); + + String responseData = null; + int code = 0; + CloseableHttpResponse response = client.execute(postMethod); + try { + code = response.getStatusLine().getStatusCode(); + InputStream responseStream = response.getEntity().getContent(); + responseData = StringUtils.read(responseStream); + } finally { + response.close(); + } + + Map result = processResponse(returnError, code, responseData); + return result; + } +} diff --git a/cloudinary-http45/src/main/java/com/cloudinary/http45/api/Response.java b/cloudinary-http45/src/main/java/com/cloudinary/http45/api/Response.java new file mode 100644 index 00000000..6cb29455 --- /dev/null +++ b/cloudinary-http45/src/main/java/com/cloudinary/http45/api/Response.java @@ -0,0 +1,69 @@ +package com.cloudinary.http45.api; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.http.Header; +import org.apache.http.HttpResponse; + +import com.cloudinary.api.ApiResponse; +import com.cloudinary.api.RateLimit; +import com.cloudinary.utils.StringUtils; + +@SuppressWarnings("rawtypes") +public class Response extends HashMap implements ApiResponse { + private static final long serialVersionUID = -5458609797599845837L; + private HttpResponse response = null; + + @SuppressWarnings("unchecked") + public Response(HttpResponse response, Map result) { + super(result); + this.response = response; + } + + public HttpResponse getRawHttpResponse() { + return this.response; + } + + private static final Pattern RATE_LIMIT_REGEX = Pattern + .compile("X-Feature(\\w*)RateLimit(-Limit|-Reset|-Remaining)"); + private static final String RFC1123_PATTERN = "EEE, dd MMM yyyyy HH:mm:ss z"; + private static final DateFormat RFC1123 = new SimpleDateFormat(RFC1123_PATTERN, Locale.ENGLISH); + + public Map rateLimits() throws java.text.ParseException { + Header[] headers = this.response.getAllHeaders(); + Map limits = new HashMap(); + for (Header header : headers) { + Matcher m = RATE_LIMIT_REGEX.matcher(header.getName()); + if (m.matches()) { + String limitName = "Api"; + RateLimit limit = null; + if (!StringUtils.isEmpty(m.group(1))) { + limitName = m.group(1); + } + limit = limits.get(limitName); + if (limit == null) { + limit = new RateLimit(); + } + if (m.group(2).equalsIgnoreCase("-limit")) { + limit.setLimit(Long.parseLong(header.getValue())); + } else if (m.group(2).equalsIgnoreCase("-remaining")) { + limit.setRemaining(Long.parseLong(header.getValue())); + } else if (m.group(2).equalsIgnoreCase("-reset")) { + limit.setReset(RFC1123.parse(header.getValue())); + } + limits.put(limitName, limit); + } + } + return limits; + } + + public RateLimit apiRateLimit() throws java.text.ParseException { + return rateLimits().get("Api"); + } +} diff --git a/cloudinary-http45/src/test/java/com/cloudinary/test/AccountApiTest.java b/cloudinary-http45/src/test/java/com/cloudinary/test/AccountApiTest.java new file mode 100644 index 00000000..573a12e5 --- /dev/null +++ b/cloudinary-http45/src/test/java/com/cloudinary/test/AccountApiTest.java @@ -0,0 +1,4 @@ +package com.cloudinary.test; + +public class AccountApiTest extends AbstractAccountApiTest { +} diff --git a/cloudinary-http45/src/test/java/com/cloudinary/test/ApiTest.java b/cloudinary-http45/src/test/java/com/cloudinary/test/ApiTest.java new file mode 100644 index 00000000..c39a89e2 --- /dev/null +++ b/cloudinary-http45/src/test/java/com/cloudinary/test/ApiTest.java @@ -0,0 +1,32 @@ +package com.cloudinary.test; + +import com.cloudinary.api.ApiResponse; +import com.cloudinary.utils.ObjectUtils; +import org.apache.http.conn.ConnectTimeoutException; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import java.net.SocketTimeoutException; +import java.util.Map; + +public class ApiTest extends AbstractApiTest { + @Category(TimeoutTest.class) + @Test(expected = ConnectTimeoutException.class) + public void testConnectTimeoutParameter() throws Exception { + // should allow listing resources + Map options = ObjectUtils.asMap( + "max_results", 500, + "connect_timeout", 1); + ApiResponse result = cloudinary.api().resources(options); + } + + @Category(TimeoutTest.class) + @Test(expected = SocketTimeoutException.class) + public void testTimeoutParameter() throws Exception { + // should allow listing resources + Map options = ObjectUtils.asMap( + "max_results", 500, + "timeout", 1); + ApiResponse result = cloudinary.api().resources(options); + } +} diff --git a/cloudinary-http45/src/test/java/com/cloudinary/test/ContextTest.java b/cloudinary-http45/src/test/java/com/cloudinary/test/ContextTest.java new file mode 100644 index 00000000..4841e9f6 --- /dev/null +++ b/cloudinary-http45/src/test/java/com/cloudinary/test/ContextTest.java @@ -0,0 +1,5 @@ +package com.cloudinary.test; + +public class ContextTest extends AbstractContextTest { + +} \ No newline at end of file diff --git a/cloudinary-http45/src/test/java/com/cloudinary/test/FoldersApiTest.java b/cloudinary-http45/src/test/java/com/cloudinary/test/FoldersApiTest.java new file mode 100644 index 00000000..971bcf39 --- /dev/null +++ b/cloudinary-http45/src/test/java/com/cloudinary/test/FoldersApiTest.java @@ -0,0 +1,4 @@ +package com.cloudinary.test; + +public class FoldersApiTest extends AbstractFoldersApiTest { +} diff --git a/cloudinary-http45/src/test/java/com/cloudinary/test/SearchTest.java b/cloudinary-http45/src/test/java/com/cloudinary/test/SearchTest.java new file mode 100644 index 00000000..16a4708c --- /dev/null +++ b/cloudinary-http45/src/test/java/com/cloudinary/test/SearchTest.java @@ -0,0 +1,4 @@ +package com.cloudinary.test; + +public class SearchTest extends AbstractSearchTest { +} diff --git a/cloudinary-http45/src/test/java/com/cloudinary/test/StreamingProfilesApiTest.java b/cloudinary-http45/src/test/java/com/cloudinary/test/StreamingProfilesApiTest.java new file mode 100644 index 00000000..6a2e8a31 --- /dev/null +++ b/cloudinary-http45/src/test/java/com/cloudinary/test/StreamingProfilesApiTest.java @@ -0,0 +1,4 @@ +package com.cloudinary.test; + +public class StreamingProfilesApiTest extends AbstractStreamingProfilesApiTest { +} diff --git a/cloudinary-http45/src/test/java/com/cloudinary/test/StructuredMetadataTest.java b/cloudinary-http45/src/test/java/com/cloudinary/test/StructuredMetadataTest.java new file mode 100644 index 00000000..8cc186f4 --- /dev/null +++ b/cloudinary-http45/src/test/java/com/cloudinary/test/StructuredMetadataTest.java @@ -0,0 +1,4 @@ +package com.cloudinary.test; + +public class StructuredMetadataTest extends AbstractStructuredMetadataTest { +} diff --git a/cloudinary-http45/src/test/java/com/cloudinary/test/UploaderTest.java b/cloudinary-http45/src/test/java/com/cloudinary/test/UploaderTest.java new file mode 100644 index 00000000..efbf9190 --- /dev/null +++ b/cloudinary-http45/src/test/java/com/cloudinary/test/UploaderTest.java @@ -0,0 +1,34 @@ +package com.cloudinary.test; + +import com.cloudinary.api.ApiResponse; +import com.cloudinary.utils.ObjectUtils; +import org.apache.http.conn.ConnectTimeoutException; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import java.net.SocketTimeoutException; +import java.util.Map; + +public class UploaderTest extends AbstractUploaderTest { + + @Category(TimeoutTest.class) + @Test(expected = ConnectTimeoutException.class) + public void testConnectTimeoutParameter() throws Exception { + // should allow listing resources + Map options = ObjectUtils.asMap( + "max_results", 500, + "connect_timeout", 1); + ApiResponse result = cloudinary.api().resources(options); + } + + @Category(TimeoutTest.class) + @Test(expected = SocketTimeoutException.class) + public void testTimeoutParameter() throws Exception { + // should allow listing resources + Map options = ObjectUtils.asMap( + "max_results", 500, + "timeout", 1); + ApiResponse result = cloudinary.api().resources(options); + } + +} \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index c1342b86..174cb41d 100644 --- a/settings.gradle +++ b/settings.gradle @@ -5,3 +5,4 @@ include ':cloudinary-test-common' include ':cloudinary-http42' include ':cloudinary-http43' include ':cloudinary-http44' +include ':cloudinary-http45' From 480518a01e966dfb0d4336a5131eab6a221a9f02 Mon Sep 17 00:00:00 2001 From: Asi Sayag <42962333+asisayag2@users.noreply.github.com> Date: Wed, 10 Feb 2021 16:32:09 +0200 Subject: [PATCH 011/150] Allow setting the user agent (#235) --- .../main/java/com/cloudinary/Cloudinary.java | 22 +++++++++++++++++-- .../com/cloudinary/http42/ApiStrategy.java | 2 +- .../cloudinary/http42/UploaderStrategy.java | 2 +- .../com/cloudinary/http43/ApiStrategy.java | 2 +- .../cloudinary/http43/UploaderStrategy.java | 2 +- .../com/cloudinary/http44/ApiStrategy.java | 2 +- .../cloudinary/http44/UploaderStrategy.java | 2 +- .../com/cloudinary/http45/ApiStrategy.java | 2 +- .../cloudinary/http45/UploaderStrategy.java | 2 +- .../com/cloudinary/test/AbstractApiTest.java | 12 +++++++++- 10 files changed, 39 insertions(+), 11 deletions(-) diff --git a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java index 1cf44999..940e0d0f 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java @@ -38,15 +38,16 @@ public class Cloudinary { public final static String SHARED_CDN = AKAMAI_SHARED_CDN; public final static String VERSION = "1.28.1"; - public final static String USER_AGENT = "CloudinaryJava/" + VERSION + " (Java " + System.getProperty("java.version") + ")"; + static String USER_AGENT_PREFIX = "CloudinaryJava"; + public final static String USER_AGENT_JAVA_VERSION = "(Java " + System.getProperty("java.version") + ")"; public final Configuration config; private AbstractUploaderStrategy uploaderStrategy; private AbstractApiStrategy apiStrategy; + private String userAgent = USER_AGENT_PREFIX+"/"+ VERSION + " "+USER_AGENT_JAVA_VERSION; public Uploader uploader() { return new Uploader(this, uploaderStrategy); - } public Api api() { @@ -135,6 +136,23 @@ public String apiSignRequest(Map paramsToSign, String apiSecret) return Util.produceSignature(paramsToSign, apiSecret, config.signatureAlgorithm); } + /** + * @return the userAgent that will be sent with every API call. + */ + public String getUserAgent(){ + return userAgent; + } + + /** + * Set the prefix and version for the user agent that will be sent with every API call + * a userAgent is built from `prefix/version (additional data)` + * @param prefix - the prefix of the userAgent to be set + * @param version - the version of the userAgent to be set + */ + public void setUserAgent(String prefix, String version){ + userAgent = prefix+"/"+ version + " ("+USER_AGENT_PREFIX+ " "+VERSION+") " + USER_AGENT_JAVA_VERSION; + } + /** * Verifies that Cloudinary notification request is genuine by checking its signature. * diff --git a/cloudinary-http42/src/main/java/com/cloudinary/http42/ApiStrategy.java b/cloudinary-http42/src/main/java/com/cloudinary/http42/ApiStrategy.java index a8aa7c93..6703448e 100644 --- a/cloudinary-http42/src/main/java/com/cloudinary/http42/ApiStrategy.java +++ b/cloudinary-http42/src/main/java/com/cloudinary/http42/ApiStrategy.java @@ -107,7 +107,7 @@ private ApiResponse getApiResponse(HttpMethod method, Map params, Str break; } request.setHeader("Authorization", getAuthorizationHeaderValue(apiKey, apiSecret, oauthToken)); - request.setHeader("User-Agent", Cloudinary.USER_AGENT + " ApacheHTTPComponents/4.2"); + request.setHeader("User-Agent", this.api.cloudinary.getUserAgent() + " ApacheHTTPComponents/4.2"); if (contentType.equals("json")) { JSONObject asJSON = ObjectUtils.toJSON(params); StringEntity requestEntity = new StringEntity(asJSON.toString(), ContentType.APPLICATION_JSON); diff --git a/cloudinary-http42/src/main/java/com/cloudinary/http42/UploaderStrategy.java b/cloudinary-http42/src/main/java/com/cloudinary/http42/UploaderStrategy.java index b34ae4ff..9984f015 100644 --- a/cloudinary-http42/src/main/java/com/cloudinary/http42/UploaderStrategy.java +++ b/cloudinary-http42/src/main/java/com/cloudinary/http42/UploaderStrategy.java @@ -60,7 +60,7 @@ public Map callApi(String action, Map params, Map options, Objec } HttpPost postMethod = new HttpPost(apiUrl); - postMethod.setHeader("User-Agent", Cloudinary.USER_AGENT + " ApacheHTTPComponents/4.2"); + postMethod.setHeader("User-Agent", this.cloudinary().getUserAgent() + " ApacheHTTPComponents/4.2"); Map extraHeaders = (Map) options.get("extra_headers"); if (extraHeaders != null) { diff --git a/cloudinary-http43/src/main/java/com/cloudinary/http43/ApiStrategy.java b/cloudinary-http43/src/main/java/com/cloudinary/http43/ApiStrategy.java index ef02ce17..04ac023e 100644 --- a/cloudinary-http43/src/main/java/com/cloudinary/http43/ApiStrategy.java +++ b/cloudinary-http43/src/main/java/com/cloudinary/http43/ApiStrategy.java @@ -47,7 +47,7 @@ public void init(Api api) { super.init(api); HttpClientBuilder clientBuilder = HttpClients.custom(); - clientBuilder.useSystemProperties().setUserAgent(Cloudinary.USER_AGENT + " ApacheHTTPComponents/4.3"); + clientBuilder.useSystemProperties().setUserAgent(this.api.cloudinary.getUserAgent() + " ApacheHTTPComponents/4.3"); // If the configuration specifies a proxy then apply it to the client if (api.cloudinary.config.proxyHost != null && api.cloudinary.config.proxyPort != 0) { diff --git a/cloudinary-http43/src/main/java/com/cloudinary/http43/UploaderStrategy.java b/cloudinary-http43/src/main/java/com/cloudinary/http43/UploaderStrategy.java index 956e9bd7..bb748f8f 100644 --- a/cloudinary-http43/src/main/java/com/cloudinary/http43/UploaderStrategy.java +++ b/cloudinary-http43/src/main/java/com/cloudinary/http43/UploaderStrategy.java @@ -37,7 +37,7 @@ public void init(Uploader uploader) { super.init(uploader); HttpClientBuilder clientBuilder = HttpClients.custom(); - clientBuilder.useSystemProperties().setUserAgent(Cloudinary.USER_AGENT + " ApacheHTTPComponents/4.3"); + clientBuilder.useSystemProperties().setUserAgent(this.cloudinary().getUserAgent() + " ApacheHTTPComponents/4.3"); // If the configuration specifies a proxy then apply it to the client if (cloudinary().config.proxyHost != null && cloudinary().config.proxyPort != 0) { diff --git a/cloudinary-http44/src/main/java/com/cloudinary/http44/ApiStrategy.java b/cloudinary-http44/src/main/java/com/cloudinary/http44/ApiStrategy.java index df8eedb3..dcd34fe2 100644 --- a/cloudinary-http44/src/main/java/com/cloudinary/http44/ApiStrategy.java +++ b/cloudinary-http44/src/main/java/com/cloudinary/http44/ApiStrategy.java @@ -49,7 +49,7 @@ public void init(Api api) { super.init(api); HttpClientBuilder clientBuilder = HttpClients.custom(); - clientBuilder.useSystemProperties().setUserAgent(Cloudinary.USER_AGENT + " ApacheHTTPComponents/4.4"); + clientBuilder.useSystemProperties().setUserAgent(this.api.cloudinary.getUserAgent() + " ApacheHTTPComponents/4.4"); // If the configuration specifies a proxy then apply it to the client if (api.cloudinary.config.proxyHost != null && api.cloudinary.config.proxyPort != 0) { diff --git a/cloudinary-http44/src/main/java/com/cloudinary/http44/UploaderStrategy.java b/cloudinary-http44/src/main/java/com/cloudinary/http44/UploaderStrategy.java index 20e18258..e075db29 100644 --- a/cloudinary-http44/src/main/java/com/cloudinary/http44/UploaderStrategy.java +++ b/cloudinary-http44/src/main/java/com/cloudinary/http44/UploaderStrategy.java @@ -38,7 +38,7 @@ public void init(Uploader uploader) { super.init(uploader); HttpClientBuilder clientBuilder = HttpClients.custom(); - clientBuilder.useSystemProperties().setUserAgent(Cloudinary.USER_AGENT + " ApacheHTTPComponents/4.4"); + clientBuilder.useSystemProperties().setUserAgent(this.cloudinary().getUserAgent() + " ApacheHTTPComponents/4.4"); // If the configuration specifies a proxy then apply it to the client if (cloudinary().config.proxyHost != null && cloudinary().config.proxyPort != 0) { diff --git a/cloudinary-http45/src/main/java/com/cloudinary/http45/ApiStrategy.java b/cloudinary-http45/src/main/java/com/cloudinary/http45/ApiStrategy.java index e7c55bf8..6b11cce9 100644 --- a/cloudinary-http45/src/main/java/com/cloudinary/http45/ApiStrategy.java +++ b/cloudinary-http45/src/main/java/com/cloudinary/http45/ApiStrategy.java @@ -47,7 +47,7 @@ public void init(Api api) { super.init(api); HttpClientBuilder clientBuilder = HttpClients.custom(); - clientBuilder.useSystemProperties().setUserAgent(Cloudinary.USER_AGENT + " ApacheHTTPComponents/4.5"); + clientBuilder.useSystemProperties().setUserAgent(this.api.cloudinary.getUserAgent() + " ApacheHTTPComponents/4.5"); // If the configuration specifies a proxy then apply it to the client if (api.cloudinary.config.proxyHost != null && api.cloudinary.config.proxyPort != 0) { diff --git a/cloudinary-http45/src/main/java/com/cloudinary/http45/UploaderStrategy.java b/cloudinary-http45/src/main/java/com/cloudinary/http45/UploaderStrategy.java index e29b07ad..175653cf 100644 --- a/cloudinary-http45/src/main/java/com/cloudinary/http45/UploaderStrategy.java +++ b/cloudinary-http45/src/main/java/com/cloudinary/http45/UploaderStrategy.java @@ -34,7 +34,7 @@ public void init(Uploader uploader) { super.init(uploader); HttpClientBuilder clientBuilder = HttpClients.custom(); - clientBuilder.useSystemProperties().setUserAgent(Cloudinary.USER_AGENT + " ApacheHTTPComponents/4.5"); + clientBuilder.useSystemProperties().setUserAgent(cloudinary().getUserAgent() + " ApacheHTTPComponents/4.5"); // If the configuration specifies a proxy then apply it to the client if (cloudinary().config.proxyHost != null && cloudinary().config.proxyPort != 0) { diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java index c94468e7..0bc51d31 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java @@ -47,6 +47,9 @@ abstract public class AbstractApiTest extends MockableTest { public static final String TEST_KEY = "test-key" + SUFFIX; public static final String API_TEST_RESTORE = "api_test_restore" + SUFFIX; public static final Set createdFolders = new HashSet(); + private static final String CUSTOM_USER_AGENT_PREFIX = "TEST_USER_AGENT"; + private static final String CUSTOM_USER_AGENT_VERSION = "9.9.9"; + protected Api api; @@ -126,7 +129,6 @@ public static void tearDownClass() { } } catch (Exception ignored) { } - } @Rule @@ -151,6 +153,14 @@ public Map findByAttr(List elements, String attr, Object value) { return null; } + @Test + public void testCustomUserAgent() throws Exception { + // should allow setting a custom user-agent + cloudinary.setUserAgent(CUSTOM_USER_AGENT_PREFIX, CUSTOM_USER_AGENT_VERSION); + Map results = api.ping(ObjectUtils.emptyMap()); + //TODO Mock server and assert the header + } + @Test public void test01ResourceTypes() throws Exception { // should allow listing resource_types From 97a54d2e02c441bb8b5b31a03ed48a52d3bad1d6 Mon Sep 17 00:00:00 2001 From: asisayag2 Date: Wed, 10 Feb 2021 17:12:49 +0200 Subject: [PATCH 012/150] Version 1.29.0 --- CHANGELOG.md | 15 ++++++++++++++- README.md | 4 ++-- .../src/main/java/com/cloudinary/Cloudinary.java | 2 +- gradle.properties | 2 +- 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c5cfd8dd..0350cb4c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,23 @@ +1.29.0 / 2021-02-10 +=================== + +New functionality +----------------- + * Allow setting the user agent (#235) + * Add support for Apache http-client 4.5 (#234) + +Other changes +------------- + * Fix test name in `ExpressionTest` (#233) + + 1.28.1 / 2021-02-03 ================== * Fix `api` reuse bug when calling `cloudinary.search()` (#232) -1.28.1 / 2021-02-01 +1.28.0 / 2021-02-01 ================== * Add `oauth` support to Admin Api calls. (#230) diff --git a/README.md b/README.md index a9d61ce0..ac8d9ee5 100644 --- a/README.md +++ b/README.md @@ -34,11 +34,11 @@ The cloudinary_java library is available in [Maven Central](https://repo1.maven. com.cloudinary cloudinary-http44 - 1.28.1 + 1.29.0 ``` -Alternatively, download cloudinary_java from [here](https://repo1.maven.org/maven2/com/cloudinary/cloudinary-core/1.28.1/cloudinary-core-1.28.1.jar) and [here](https://repo1.maven.org/maven2/com/cloudinary/cloudinary-http44/1.28.1/cloudinary-http44-1.28.1.jar) +Alternatively, download cloudinary_java from [here](https://repo1.maven.org/maven2/com/cloudinary/cloudinary-core/1.29.0/cloudinary-core-1.29.0.jar) and [here](https://repo1.maven.org/maven2/com/cloudinary/cloudinary-http44/1.29.0/cloudinary-http44-1.29.0.jar) and see [build.gradle](https://github.com/cloudinary/cloudinary_java/blob/master/cloudinary-http44/build.gradle) for library dependencies. ## Try it right away diff --git a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java index 940e0d0f..75cb5100 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java @@ -37,7 +37,7 @@ public class Cloudinary { public final static String AKAMAI_SHARED_CDN = "res.cloudinary.com"; public final static String SHARED_CDN = AKAMAI_SHARED_CDN; - public final static String VERSION = "1.28.1"; + public final static String VERSION = "1.29.0"; static String USER_AGENT_PREFIX = "CloudinaryJava"; public final static String USER_AGENT_JAVA_VERSION = "(Java " + System.getProperty("java.version") + ")"; diff --git a/gradle.properties b/gradle.properties index 484fccbd..ef9fd370 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,7 +13,7 @@ developerEmail=info@cloudinary.com # These two properties must use these exact names to be compatible with 'gradle install' plugin. group=com.cloudinary -version=1.28.1 +version=1.29.0 gnsp.disableApplyOnlyOnRootProjectEnforcement=true From 8061519d940b19d1cda13c347e841890764e7f58 Mon Sep 17 00:00:00 2001 From: asisayag2 Date: Mon, 3 May 2021 14:29:39 +0300 Subject: [PATCH 013/150] updated expected text that returns from the server --- .../com/cloudinary/test/AbstractStructuredMetadataTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractStructuredMetadataTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractStructuredMetadataTest.java index e073e442..7b06c557 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractStructuredMetadataTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractStructuredMetadataTest.java @@ -204,7 +204,7 @@ public void testExplicitWithMetadata() throws Exception { message = e.getMessage(); } - assertTrue(message.contains("Value 12 is invalid for field") ); + assertTrue(message.contains("is not valid for field") ); } @Test From eac25a15db12fc096d768f7fec27caa44095fc8a Mon Sep 17 00:00:00 2001 From: asisayag2 Date: Tue, 11 May 2021 14:21:28 +0300 Subject: [PATCH 014/150] Add test for double underscore in layers --- .../src/test/java/com/cloudinary/transformation/LayerTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cloudinary-core/src/test/java/com/cloudinary/transformation/LayerTest.java b/cloudinary-core/src/test/java/com/cloudinary/transformation/LayerTest.java index ad5e6e17..155ff091 100644 --- a/cloudinary-core/src/test/java/com/cloudinary/transformation/LayerTest.java +++ b/cloudinary-core/src/test/java/com/cloudinary/transformation/LayerTest.java @@ -64,6 +64,8 @@ public void testLayerOptions() { Object tests[] = { new Layer().publicId("logo"), "logo", + new Layer().publicId("logo__111"), //testing SNI-4729 + "logo__111", new Layer().publicId("folder/logo"), "folder:logo", new Layer().publicId("logo").type("private"), From 6481c37c5ab75249e6141e6184029f74e27ac1e9 Mon Sep 17 00:00:00 2001 From: asisayag2 Date: Tue, 11 May 2021 14:22:19 +0300 Subject: [PATCH 015/150] Added users cleanup on account testing to avoid "too many users" errors. --- .../test/AbstractAccountApiTest.java | 30 +++++++++++++++---- 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractAccountApiTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractAccountApiTest.java index 549f4543..b1a5ac0c 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractAccountApiTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractAccountApiTest.java @@ -151,8 +151,10 @@ public void testDeleteSubAccount() throws Exception { @Test public void testGetUser() throws Exception { ApiResponse user = createUser(); - ApiResponse result = account.user(user.get("id").toString(), null); + String id = user.get("id").toString(); + ApiResponse result = account.user(id, null); assertNotNull(result); + deleteUser(id); } @Test @@ -171,6 +173,9 @@ public void testGetUsers() throws Exception { assertTrue("User1 id should be in the result set", returnedIds.contains(id1)); assertTrue("User2 id should be in the result set", returnedIds.contains(id2)); + deleteUser(id1); + deleteUser(id2); + } @Test @@ -183,11 +188,12 @@ public void testCreateUser() throws Exception { @Test public void testUpdateUser() throws Exception { ApiResponse user = createUser(Account.Role.ADMIN); - + String id = user.get("id").toString(); String newName = randomLetters(); - ApiResponse result = account.updateUser(user.get("id").toString(), newName, null, null, null, null); + ApiResponse result = account.updateUser(id, newName, null, null, null, null); assertNotNull(result); assertEquals(result.get("name"), newName); + deleteUser(id); } @Test @@ -228,8 +234,10 @@ public void testDeleteUserGroup() throws Exception { public void testAddUserToUserGroup() throws Exception { ApiResponse user = createUser(); ApiResponse group = createGroup(); - ApiResponse result = account.addUserToGroup(group.get("id").toString(), user.get("id").toString(), null); + String userId = user.get("id").toString(); + ApiResponse result = account.addUserToGroup(group.get("id").toString(), userId, null); assertNotNull(result); + deleteUser(userId); } @Test @@ -241,6 +249,7 @@ public void testRemoveUserFromUserGroup() throws Exception { account.addUserToGroup(groupId, userId, null); ApiResponse result = account.removeUserFromGroup(groupId, userId, null); assertNotNull(result); + deleteUser(userId); } @Test @@ -271,6 +280,8 @@ public void testListUsersInGroup() throws Exception { ApiResponse result = account.userGroupUsers(groupId, null); assertNotNull(result); assertTrue(((List) result.get("users")).size() >= 2); + deleteUser(user1Id); + deleteUser(user2Id); } @@ -280,7 +291,6 @@ private ApiResponse createGroup() throws Exception { ApiResponse userGroup = account.createUserGroup(name); createdGroupIds.add(userGroup.get("id").toString()); return userGroup; - } private ApiResponse createUser(Account.Role role) throws Exception { @@ -313,7 +323,15 @@ private static String randomLetters() { for (int i = 0; i < 10; i++) { sb.append((char) ('a' + rand.nextInt('z' - 'a' + 1))); } - return sb.toString(); } + + private void deleteUser(String userId) { + try { + account.deleteUser(userId, null); + createdUserIds.remove(userId); + } catch (Exception e) { + e.printStackTrace(); + } + } } From d2f66adae5eff63bc581d19b8abc4f08960f274e Mon Sep 17 00:00:00 2001 From: asisayag2 Date: Wed, 12 May 2021 16:36:25 +0300 Subject: [PATCH 016/150] Remove unneeded comment --- .../src/test/java/com/cloudinary/transformation/LayerTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cloudinary-core/src/test/java/com/cloudinary/transformation/LayerTest.java b/cloudinary-core/src/test/java/com/cloudinary/transformation/LayerTest.java index 155ff091..dba71ee7 100644 --- a/cloudinary-core/src/test/java/com/cloudinary/transformation/LayerTest.java +++ b/cloudinary-core/src/test/java/com/cloudinary/transformation/LayerTest.java @@ -64,7 +64,7 @@ public void testLayerOptions() { Object tests[] = { new Layer().publicId("logo"), "logo", - new Layer().publicId("logo__111"), //testing SNI-4729 + new Layer().publicId("logo__111"), "logo__111", new Layer().publicId("folder/logo"), "folder:logo", From 2f29d8ee94354282e9823683993569a508c53c5c Mon Sep 17 00:00:00 2001 From: asisayag2 Date: Sat, 15 May 2021 00:01:35 +0300 Subject: [PATCH 017/150] Removed the local users clean-up --- .../test/AbstractAccountApiTest.java | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractAccountApiTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractAccountApiTest.java index b1a5ac0c..b8e4f549 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractAccountApiTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractAccountApiTest.java @@ -154,7 +154,6 @@ public void testGetUser() throws Exception { String id = user.get("id").toString(); ApiResponse result = account.user(id, null); assertNotNull(result); - deleteUser(id); } @Test @@ -173,9 +172,6 @@ public void testGetUsers() throws Exception { assertTrue("User1 id should be in the result set", returnedIds.contains(id1)); assertTrue("User2 id should be in the result set", returnedIds.contains(id2)); - deleteUser(id1); - deleteUser(id2); - } @Test @@ -193,7 +189,6 @@ public void testUpdateUser() throws Exception { ApiResponse result = account.updateUser(id, newName, null, null, null, null); assertNotNull(result); assertEquals(result.get("name"), newName); - deleteUser(id); } @Test @@ -237,7 +232,6 @@ public void testAddUserToUserGroup() throws Exception { String userId = user.get("id").toString(); ApiResponse result = account.addUserToGroup(group.get("id").toString(), userId, null); assertNotNull(result); - deleteUser(userId); } @Test @@ -249,7 +243,6 @@ public void testRemoveUserFromUserGroup() throws Exception { account.addUserToGroup(groupId, userId, null); ApiResponse result = account.removeUserFromGroup(groupId, userId, null); assertNotNull(result); - deleteUser(userId); } @Test @@ -280,8 +273,6 @@ public void testListUsersInGroup() throws Exception { ApiResponse result = account.userGroupUsers(groupId, null); assertNotNull(result); assertTrue(((List) result.get("users")).size() >= 2); - deleteUser(user1Id); - deleteUser(user2Id); } @@ -325,13 +316,4 @@ private static String randomLetters() { } return sb.toString(); } - - private void deleteUser(String userId) { - try { - account.deleteUser(userId, null); - createdUserIds.remove(userId); - } catch (Exception e) { - e.printStackTrace(); - } - } } From 73751bebd9f505e419131d21ac155adfde7fc3cf Mon Sep 17 00:00:00 2001 From: asisayag2 Date: Mon, 2 Aug 2021 14:50:55 +0300 Subject: [PATCH 018/150] Added users deletion at the end of tests --- .../test/AbstractAccountApiTest.java | 42 ++++++++++++++----- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractAccountApiTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractAccountApiTest.java index b8e4f549..a5d00fcb 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractAccountApiTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractAccountApiTest.java @@ -38,6 +38,7 @@ public void setUp() throws Exception { @AfterClass public static void tearDownClass() { + System.out.println("Start TearDownClass"); Account account = new Account(new Cloudinary()); for (String createdSubAccountId : createdSubAccountIds) { try { @@ -62,6 +63,7 @@ public static void tearDownClass() { e.printStackTrace(); } } + System.out.println("### Deleted - SubAccounts:"+createdSubAccountIds.size()+", Users:"+createdUserIds.size()+ ", UserGroups:"+createdGroupIds.size()); } @Test @@ -151,16 +153,18 @@ public void testDeleteSubAccount() throws Exception { @Test public void testGetUser() throws Exception { ApiResponse user = createUser(); - String id = user.get("id").toString(); - ApiResponse result = account.user(id, null); + String userId = user.get("id").toString(); + ApiResponse result = account.user(userId, null); + assertNotNull(result); + deleteUser(userId); } @Test public void testGetUsers() throws Exception { - String id1 = createUser(Account.Role.MASTER_ADMIN).get("id").toString(); - String id2 = createUser(Account.Role.MASTER_ADMIN).get("id").toString(); - ApiResponse result = account.users(null, Arrays.asList(id1, id2), null, null, null); + String user1Id = createUser(Account.Role.MASTER_ADMIN).get("id").toString(); + String user2Id = createUser(Account.Role.MASTER_ADMIN).get("id").toString(); + ApiResponse result = account.users(null, Arrays.asList(user1Id, user2Id), null, null, null); assertNotNull(result); final ArrayList users = (ArrayList) result.get("users"); ArrayList returnedIds = new ArrayList(2); @@ -170,8 +174,10 @@ public void testGetUsers() throws Exception { returnedIds.add(((Map) users.get(0)).get("id").toString()); returnedIds.add(((Map) users.get(1)).get("id").toString()); - assertTrue("User1 id should be in the result set", returnedIds.contains(id1)); - assertTrue("User2 id should be in the result set", returnedIds.contains(id2)); + assertTrue("User1 id should be in the result set", returnedIds.contains(user1Id)); + assertTrue("User2 id should be in the result set", returnedIds.contains(user2Id)); + deleteUser(user1Id); + deleteUser(user2Id); } @Test @@ -184,11 +190,13 @@ public void testCreateUser() throws Exception { @Test public void testUpdateUser() throws Exception { ApiResponse user = createUser(Account.Role.ADMIN); - String id = user.get("id").toString(); + String userId = user.get("id").toString(); String newName = randomLetters(); - ApiResponse result = account.updateUser(id, newName, null, null, null, null); + ApiResponse result = account.updateUser(userId, newName, null, null, null, null); + assertNotNull(result); assertEquals(result.get("name"), newName); + deleteUser(userId); } @Test @@ -232,6 +240,7 @@ public void testAddUserToUserGroup() throws Exception { String userId = user.get("id").toString(); ApiResponse result = account.addUserToGroup(group.get("id").toString(), userId, null); assertNotNull(result); + deleteUser(userId); } @Test @@ -243,6 +252,7 @@ public void testRemoveUserFromUserGroup() throws Exception { account.addUserToGroup(groupId, userId, null); ApiResponse result = account.removeUserFromGroup(groupId, userId, null); assertNotNull(result); + deleteUser(userId); } @Test @@ -273,6 +283,8 @@ public void testListUsersInGroup() throws Exception { ApiResponse result = account.userGroupUsers(groupId, null); assertNotNull(result); assertTrue(((List) result.get("users")).size() >= 2); + deleteUser(user1Id); + deleteUser(user2Id); } @@ -298,11 +310,21 @@ private ApiResponse createUser(List subAccountsIds) throws Exception { private ApiResponse createUser(List subAccountsIds, Account.Role role) throws Exception { String email = String.format("%s@%s.com", randomLetters(), randomLetters()); - ApiResponse user = account.createUser("TestName", email, role, subAccountsIds, null); + ApiResponse user = account.createUser("TestUserJava"+new Date().toString(), email, role, subAccountsIds, null); createdUserIds.add(user.get("id").toString()); return user; } + private void deleteUser(String userId){ + try { + account.deleteUser(userId, null); + createdUserIds.remove(userId); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private ApiResponse createSubAccount() throws Exception { ApiResponse subAccount = account.createSubAccount(randomLetters(), null, emptyMap(), true, null); createdSubAccountIds.add(subAccount.get("id").toString()); From 652dd201458e2693c032b6e3466d9a40ef1b4ec4 Mon Sep 17 00:00:00 2001 From: patrick-tolosa <59408474+patrick-tolosa@users.noreply.github.com> Date: Sun, 19 Sep 2021 11:52:33 +0300 Subject: [PATCH 019/150] Update Configuration.java --- cloudinary-core/src/main/java/com/cloudinary/Configuration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cloudinary-core/src/main/java/com/cloudinary/Configuration.java b/cloudinary-core/src/main/java/com/cloudinary/Configuration.java index 18e813ce..199071f2 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Configuration.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Configuration.java @@ -312,7 +312,7 @@ public static class Builder { /** * Set the HTTP connection timeout. * - * @param timeout time in milliseconds, or 0 to use the default platform value + * @param timeout time in seconds, or 0 to use the default platform value * @return builder for chaining */ public Builder setTimeout(int timeout) { From 4fffc8b8aef4c0757ffd662ad2b23bb25b69b7d4 Mon Sep 17 00:00:00 2001 From: patrick-tolosa <59408474+patrick-tolosa@users.noreply.github.com> Date: Thu, 14 Oct 2021 17:11:30 +0300 Subject: [PATCH 020/150] Add email notification to Travis build --- .travis.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.travis.yml b/.travis.yml index d71e7b1e..15fbae01 100644 --- a/.travis.yml +++ b/.travis.yml @@ -31,3 +31,9 @@ before_script: ./gradlew createTestSubAccount -PmoduleName=${MODULE} # ciTest is configured to skip the various timeout tests that don't work in travis script: source tools/cloudinary_url.txt && ./gradlew -DCLOUDINARY_URL=$CLOUDINARY_URL -DCLOUDINARY_ACCOUNT_URL=$CLOUDINARY_ACCOUNT_URL ciTest -p cloudinary-${MODULE} -i + + +notifications: + email: + recipients: + - sdk_developers@cloudinary.com From df7b3cca08c165a2fc28dc9ef72e9db2520b6009 Mon Sep 17 00:00:00 2001 From: Asi Sayag <42962333+asisayag2@users.noreply.github.com> Date: Wed, 27 Oct 2021 18:29:03 +0300 Subject: [PATCH 021/150] Fix a bug where a publicId which contains 'v[num]' is considered to contain a version, therefore the version is skipped. (#242) --- .../src/main/java/com/cloudinary/Url.java | 2 +- .../com/cloudinary/utils/StringUtils.java | 25 ++++---------- .../test/java/com/cloudinary/UtilTest.java | 33 ++++++++++++------- .../com/cloudinary/test/CloudinaryTest.java | 8 +++++ java_shared.gradle | 4 +-- 5 files changed, 39 insertions(+), 33 deletions(-) diff --git a/cloudinary-core/src/main/java/com/cloudinary/Url.java b/cloudinary-core/src/main/java/com/cloudinary/Url.java index fad9ece8..e8cc7e38 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Url.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Url.java @@ -377,7 +377,7 @@ public String generate(String source) { source = finalizedSource[0]; String sourceToSign = finalizedSource[1]; - if (this.config.forceVersion && sourceToSign.contains("/") && !StringUtils.hasVersionString(sourceToSign) && + if (this.config.forceVersion && sourceToSign.contains("/") && !StringUtils.startWithVersionString(sourceToSign) && !httpSource && StringUtils.isEmpty(version)) { version = "1"; } diff --git a/cloudinary-core/src/main/java/com/cloudinary/utils/StringUtils.java b/cloudinary-core/src/main/java/com/cloudinary/utils/StringUtils.java index 73ddf45d..3149e018 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/utils/StringUtils.java +++ b/cloudinary-core/src/main/java/com/cloudinary/utils/StringUtils.java @@ -340,26 +340,15 @@ public static String removeStartingChars(String s, char c) { } /** - * Checks whether the url contains a versioning string (v + number, e.g. v12345) - * @param url The url to check - * @return Whether a version string is contained within the url + * Checks whether a publicId starts a versioning string (v + number, e.g. v12345) + * @param publicId The url to check + * @return Whether a version string is contained within the publicId */ - public static boolean hasVersionString(String url) { - boolean inVersion = false; - for (int i = 0; i < url.length(); i++) { - char c = url.charAt(i); - if (c == 'v') { - inVersion = true; - } else if (Character.isDigit(c) && inVersion) { - return true; - } else { - inVersion = false; - } - - + public static boolean startWithVersionString(String publicId){ + if (publicId.startsWith("/")){ + publicId = publicId.substring(1); } - - return false; + return publicId.length()>1 && publicId.startsWith("v") && Character.isDigit(publicId.charAt(1)); } /** diff --git a/cloudinary-core/src/test/java/com/cloudinary/UtilTest.java b/cloudinary-core/src/test/java/com/cloudinary/UtilTest.java index a8c7b0ba..8f8f5e15 100644 --- a/cloudinary-core/src/test/java/com/cloudinary/UtilTest.java +++ b/cloudinary-core/src/test/java/com/cloudinary/UtilTest.java @@ -129,18 +129,27 @@ public void testMergeSlashes(){ } @Test - public void testHasVersionString(){ - assertTrue(StringUtils.hasVersionString("wqeasdlv31423423")); - assertTrue(StringUtils.hasVersionString("v1")); - assertTrue(StringUtils.hasVersionString("v1fdasfasd")); - assertTrue(StringUtils.hasVersionString("asdasv1fdasfasd")); - assertTrue(StringUtils.hasVersionString("12v1fdasfasd")); - - assertFalse(StringUtils.hasVersionString("121fdasfasd")); - assertFalse(StringUtils.hasVersionString("")); - assertFalse(StringUtils.hasVersionString("vvv")); - assertFalse(StringUtils.hasVersionString("v")); - assertFalse(StringUtils.hasVersionString("asdvvv")); + public void testStartWithVersionString(){ + assertTrue(StringUtils.startWithVersionString("v1")); + assertTrue(StringUtils.startWithVersionString("v1fdasfasd")); + assertTrue(StringUtils.startWithVersionString("v112fdasfasd")); + assertTrue(StringUtils.startWithVersionString("v112/fda/sfasd")); + assertTrue(StringUtils.startWithVersionString("v112/fda/v1sfasd")); + assertTrue(StringUtils.startWithVersionString("/v112/fda/v1sfasd")); + + assertFalse(StringUtils.startWithVersionString("asdasv1fdasfasd")); + assertFalse(StringUtils.startWithVersionString("12v1fdasfasd")); + assertFalse(StringUtils.startWithVersionString("asdasv1fdasfasd")); + assertFalse(StringUtils.startWithVersionString("wqeasdlv31423423")); + assertFalse(StringUtils.startWithVersionString("wqeasdl/v31423423")); + assertFalse(StringUtils.startWithVersionString("121fdasfasd")); + assertFalse(StringUtils.startWithVersionString("/121fdasfasd")); + assertFalse(StringUtils.startWithVersionString("/")); + assertFalse(StringUtils.startWithVersionString("/v")); + assertFalse(StringUtils.startWithVersionString("")); + assertFalse(StringUtils.startWithVersionString("vvv")); + assertFalse(StringUtils.startWithVersionString("v")); + assertFalse(StringUtils.startWithVersionString("asdvvv")); } @Test diff --git a/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java b/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java index e0875980..109b44ed 100644 --- a/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java +++ b/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java @@ -636,6 +636,14 @@ public void testFoldersWithExcludeVersion() { result = cloudinary.url().generate("folder/test"); assertEquals(DEFAULT_UPLOAD_PATH + "v1/folder/test", result); + // should not add version if the path STARTS with 'v[num]' + result = cloudinary.url().generate("v1234/folder/test"); + assertEquals(DEFAULT_UPLOAD_PATH + "v1234/folder/test", result); + + // should add version if the path CONTAINS 'v[num]' + result = cloudinary.url().generate("folder/v123test"); + assertEquals(DEFAULT_UPLOAD_PATH + "v1/folder/v123test", result); + // should add version if forceVersion is true result = cloudinary.url().forceVersion(true).generate("folder/test"); assertEquals(DEFAULT_UPLOAD_PATH + "v1/folder/test", result); diff --git a/java_shared.gradle b/java_shared.gradle index b9396ad2..134636f7 100644 --- a/java_shared.gradle +++ b/java_shared.gradle @@ -1,5 +1,5 @@ -sourceCompatibility = 1.6 -targetCompatibility = 1.6 +sourceCompatibility = 1.7 +targetCompatibility = 1.7 javadoc { options.encoding = 'UTF-8' From 2d8c1ebdb20ae01b43766d6100556eefb177edf6 Mon Sep 17 00:00:00 2001 From: adimiz1 Date: Sun, 23 Jan 2022 15:34:10 +0200 Subject: [PATCH 022/150] Add analytics support to url-gen --- .../src/main/java/com/cloudinary/Cloudinary.java | 9 +++++++++ .../src/main/java/com/cloudinary/Url.java | 4 ++++ .../com/cloudinary/utils/AnalyticsUtils.java | 6 ++++++ .../java/com/cloudinary/test/CloudinaryTest.java | 16 ++++++++++++++++ 4 files changed, 35 insertions(+) create mode 100644 cloudinary-core/src/main/java/com/cloudinary/utils/AnalyticsUtils.java diff --git a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java index 75cb5100..18739ca0 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java @@ -5,6 +5,7 @@ import com.cloudinary.strategies.AbstractApiStrategy; import com.cloudinary.strategies.AbstractUploaderStrategy; import com.cloudinary.strategies.StrategyLoader; +import com.cloudinary.utils.AnalyticsUtils; import com.cloudinary.utils.ObjectUtils; import com.cloudinary.utils.StringUtils; @@ -153,6 +154,14 @@ public void setUserAgent(String prefix, String version){ userAgent = prefix+"/"+ version + " ("+USER_AGENT_PREFIX+ " "+VERSION+") " + USER_AGENT_JAVA_VERSION; } + /** + * Set the analytics token that will be sent with every URL generate call + * @param token - the analytics token to be set + */ + public void setAnalyticsToken(String token) { + AnalyticsUtils.token = token; + } + /** * Verifies that Cloudinary notification request is genuine by checking its signature. * diff --git a/cloudinary-core/src/main/java/com/cloudinary/Url.java b/cloudinary-core/src/main/java/com/cloudinary/Url.java index e8cc7e38..9ead079f 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Url.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Url.java @@ -13,6 +13,7 @@ import java.util.regex.Pattern; import java.util.zip.CRC32; +import com.cloudinary.utils.AnalyticsUtils; import com.cloudinary.utils.Base64Coder; import com.cloudinary.utils.ObjectUtils; import com.cloudinary.utils.StringUtils; @@ -417,6 +418,9 @@ public String generate(String source) { } catch (MalformedURLException ignored) { } } + if (AnalyticsUtils.token != null) { + url = (new StringBuilder()).append(url).append(AnalyticsUtils.analyticsPrefix).append(AnalyticsUtils.token).toString(); + } return url; } diff --git a/cloudinary-core/src/main/java/com/cloudinary/utils/AnalyticsUtils.java b/cloudinary-core/src/main/java/com/cloudinary/utils/AnalyticsUtils.java new file mode 100644 index 00000000..3939c760 --- /dev/null +++ b/cloudinary-core/src/main/java/com/cloudinary/utils/AnalyticsUtils.java @@ -0,0 +1,6 @@ +package com.cloudinary.utils; + +public class AnalyticsUtils { + public static String analyticsPrefix = "?_a="; + public static String token = null; +} diff --git a/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java b/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java index 109b44ed..a7cf8898 100644 --- a/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java +++ b/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java @@ -2,6 +2,7 @@ import com.cloudinary.*; import com.cloudinary.transformation.*; +import com.cloudinary.utils.AnalyticsUtils; import com.cloudinary.utils.ObjectUtils; import junitparams.JUnitParamsRunner; import junitparams.Parameters; @@ -1454,4 +1455,19 @@ private void setRandomValue(Random rand, Field field, Object instance) throws Il private > T randomEnum(Class clazz, Random random) { return clazz.getEnumConstants()[random.nextInt(clazz.getEnumConstants().length)]; } + + @Test + public void testUrlWithAnalytics() { + AnalyticsUtils.token = "AFAACAI0"; + String url = cloudinary.url().generate("test"); + assertEquals(url,"http://res.cloudinary.com/test123/image/upload/test?_a=AFAACAI0"); + AnalyticsUtils.token = null; + } + + @Test + public void testUrlWithNoAnalytics() { + AnalyticsUtils.token = null; + String url = cloudinary.url().generate("test"); + assertEquals(url,"http://res.cloudinary.com/test123/image/upload/test"); + } } From b650f8e95ab3328b4b387eefba98d9905675dd53 Mon Sep 17 00:00:00 2001 From: adimiz1 Date: Mon, 24 Jan 2022 14:05:54 +0200 Subject: [PATCH 023/150] Add support to analytics if query params already exist --- .../src/main/java/com/cloudinary/Url.java | 4 +++- .../java/com/cloudinary/utils/AnalyticsUtils.java | 15 +++++++++++++++ .../test/java/com/cloudinary/AuthTokenTest.java | 10 ++++++++++ .../java/com/cloudinary/test/CloudinaryTest.java | 2 ++ 4 files changed, 30 insertions(+), 1 deletion(-) diff --git a/cloudinary-core/src/main/java/com/cloudinary/Url.java b/cloudinary-core/src/main/java/com/cloudinary/Url.java index 9ead079f..7862d0b4 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Url.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Url.java @@ -419,7 +419,9 @@ public String generate(String source) { } } if (AnalyticsUtils.token != null) { - url = (new StringBuilder()).append(url).append(AnalyticsUtils.analyticsPrefix).append(AnalyticsUtils.token).toString(); + if(!AnalyticsUtils.checkIfQueryParamExist(url)) { + url = (new StringBuilder()).append(url).append(AnalyticsUtils.analyticsPrefix).append(AnalyticsUtils.token).toString(); + } } return url; } diff --git a/cloudinary-core/src/main/java/com/cloudinary/utils/AnalyticsUtils.java b/cloudinary-core/src/main/java/com/cloudinary/utils/AnalyticsUtils.java index 3939c760..c055dc96 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/utils/AnalyticsUtils.java +++ b/cloudinary-core/src/main/java/com/cloudinary/utils/AnalyticsUtils.java @@ -1,6 +1,21 @@ package com.cloudinary.utils; +import java.net.MalformedURLException; +import java.net.URL; + public class AnalyticsUtils { public static String analyticsPrefix = "?_a="; public static String token = null; + + public static Boolean checkIfQueryParamExist(String urlString) { + try { + URL url = new URL(urlString); + if (url.getQuery() == null) { + return false; + } + } catch (MalformedURLException e) { + return true; + } + return true; + } } diff --git a/cloudinary-core/src/test/java/com/cloudinary/AuthTokenTest.java b/cloudinary-core/src/test/java/com/cloudinary/AuthTokenTest.java index 90b278ee..f97e2e88 100644 --- a/cloudinary-core/src/test/java/com/cloudinary/AuthTokenTest.java +++ b/cloudinary-core/src/test/java/com/cloudinary/AuthTokenTest.java @@ -1,5 +1,6 @@ package com.cloudinary; +import com.cloudinary.utils.AnalyticsUtils; import org.hamcrest.Matchers; import org.junit.Before; import org.junit.Rule; @@ -92,6 +93,15 @@ public void testAuthenticatedUrl() { } + @Test + public void testUrlAnalyticsWithQueryParams() { + cloudinary.config.privateCdn = true; + String url = cloudinary.url().signed(true).type("authenticated").generate("test"); + assertEquals(url,"http://test123-res.cloudinary.com/image/authenticated/test?__cld_token__=st=11111111~exp=11111411~hmac=735a49389a72ac0b90d1a84ac5d43facd1a9047f153b39e914747ef6ed195e53"); + AnalyticsUtils.token = null; + cloudinary.config.privateCdn = false; + } + @Test public void testConfiguration() { cloudinary = new Cloudinary("cloudinary://a:b@test123?load_strategies=false&auth_token[key]=aabbcc112233&auth_token[duration]=200"); diff --git a/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java b/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java index a7cf8898..15cb52d7 100644 --- a/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java +++ b/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java @@ -1470,4 +1470,6 @@ public void testUrlWithNoAnalytics() { String url = cloudinary.url().generate("test"); assertEquals(url,"http://res.cloudinary.com/test123/image/upload/test"); } + + } From ea3c262edce887ab6a02f0ced485d366539930fa Mon Sep 17 00:00:00 2001 From: adimiz1 Date: Sun, 30 Jan 2022 16:30:58 +0200 Subject: [PATCH 024/150] Add Analytics support --- .../main/java/com/cloudinary/Cloudinary.java | 13 +- .../java/com/cloudinary/Configuration.java | 20 +++- .../src/main/java/com/cloudinary/Url.java | 14 ++- .../java/com/cloudinary/utils/Analytics.java | 113 ++++++++++++++++++ .../com/cloudinary/utils/AnalyticsUtils.java | 21 ---- .../java/com/cloudinary/utils/Base64Map.java | 76 ++++++++++++ .../com/cloudinary/utils/StringUtils.java | 56 ++++++++- .../java/com/cloudinary/AuthTokenTest.java | 5 +- .../cloudinary/analytics/AnalyticsTest.java | 93 ++++++++++++++ .../com/cloudinary/test/CloudinaryTest.java | 18 --- java_shared.gradle | 1 + 11 files changed, 373 insertions(+), 57 deletions(-) create mode 100644 cloudinary-core/src/main/java/com/cloudinary/utils/Analytics.java delete mode 100644 cloudinary-core/src/main/java/com/cloudinary/utils/AnalyticsUtils.java create mode 100644 cloudinary-core/src/main/java/com/cloudinary/utils/Base64Map.java create mode 100644 cloudinary-core/src/test/java/com/cloudinary/analytics/AnalyticsTest.java diff --git a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java index 18739ca0..8b0b462a 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java @@ -5,7 +5,7 @@ import com.cloudinary.strategies.AbstractApiStrategy; import com.cloudinary.strategies.AbstractUploaderStrategy; import com.cloudinary.strategies.StrategyLoader; -import com.cloudinary.utils.AnalyticsUtils; +import com.cloudinary.utils.Analytics; import com.cloudinary.utils.ObjectUtils; import com.cloudinary.utils.StringUtils; @@ -46,7 +46,7 @@ public class Cloudinary { private AbstractUploaderStrategy uploaderStrategy; private AbstractApiStrategy apiStrategy; private String userAgent = USER_AGENT_PREFIX+"/"+ VERSION + " "+USER_AGENT_JAVA_VERSION; - + public Analytics analytics; public Uploader uploader() { return new Uploader(this, uploaderStrategy); } @@ -155,11 +155,12 @@ public void setUserAgent(String prefix, String version){ } /** - * Set the analytics token that will be sent with every URL generate call - * @param token - the analytics token to be set + * Set the prefix and version for the user agent that will be sent with every API call + * a userAgent is built from `prefix/version (additional data)` + * @param analytics - the analytics objec to set */ - public void setAnalyticsToken(String token) { - AnalyticsUtils.token = token; + public void setAnalytics(Analytics analytics) { + this.analytics = analytics; } /** diff --git a/cloudinary-core/src/main/java/com/cloudinary/Configuration.java b/cloudinary-core/src/main/java/com/cloudinary/Configuration.java index 199071f2..9d3cc039 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Configuration.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Configuration.java @@ -48,7 +48,7 @@ public class Configuration { public boolean longUrlSignature = DEFAULT_IS_LONG_SIGNATURE; public SignatureAlgorithm signatureAlgorithm = DEFAULT_SIGNATURE_ALGORITHM; public String oauthToken = null; - + public Boolean analytics; public Configuration() { } @@ -73,7 +73,8 @@ private Configuration( boolean forceVersion, boolean longUrlSignature, SignatureAlgorithm signatureAlgorithm, - String oauthToken) { + String oauthToken, + boolean analytics) { this.cloudName = cloudName; this.apiKey = apiKey; this.apiSecret = apiSecret; @@ -95,6 +96,7 @@ private Configuration( this.longUrlSignature = longUrlSignature; this.signatureAlgorithm = signatureAlgorithm; this.oauthToken = oauthToken; + this.analytics = analytics; } @SuppressWarnings("rawtypes") @@ -122,6 +124,7 @@ public void update(Map config) { this.loadStrategies = ObjectUtils.asBoolean(config.get("load_strategies"), true); this.timeout = ObjectUtils.asInteger(config.get("timeout"), 0); this.clientHints = ObjectUtils.asBoolean(config.get("client_hints"), false); + this.analytics = ObjectUtils.asBoolean(config.get("analytics"), null); Map tokenMap = (Map) config.get("auth_token"); if (tokenMap != null) { this.authToken = new AuthToken(tokenMap); @@ -134,6 +137,7 @@ public void update(Map config) { this.longUrlSignature = ObjectUtils.asBoolean(config.get("long_url_signature"), DEFAULT_IS_LONG_SIGNATURE); this.signatureAlgorithm = SignatureAlgorithm.valueOf(ObjectUtils.asString(config.get(CONFIG_PROP_SIGNATURE_ALGORITHM), DEFAULT_SIGNATURE_ALGORITHM.name())); this.oauthToken = (String) config.get("oauth_token"); + } @SuppressWarnings("rawtypes") @@ -165,6 +169,7 @@ public Map asMap() { map.put("long_url_signature", longUrlSignature); map.put(CONFIG_PROP_SIGNATURE_ALGORITHM, signatureAlgorithm.toString()); map.put("oauth_token", oauthToken); + map.put("analytics", analytics); return map; } @@ -196,6 +201,7 @@ public Configuration(Configuration other) { this.longUrlSignature = other.longUrlSignature; this.signatureAlgorithm = other.signatureAlgorithm; this.oauthToken = other.oauthToken; + this.analytics = other.analytics; } /** @@ -308,6 +314,7 @@ public static class Builder { private boolean longUrlSignature = DEFAULT_IS_LONG_SIGNATURE; private SignatureAlgorithm signatureAlgorithm = DEFAULT_SIGNATURE_ALGORITHM; private String oauthToken = null; + private boolean analytics; /** * Set the HTTP connection timeout. @@ -345,7 +352,8 @@ public Configuration build() { forceVersion, longUrlSignature, signatureAlgorithm, - oauthToken); + oauthToken, + analytics); configuration.clientHints = clientHints; return configuration; } @@ -450,6 +458,11 @@ public Builder setLoadStrategies(boolean loadStrategies) { return this; } + public Builder setAnalytics(boolean analytics) { + this.analytics = analytics; + return this; + } + public Builder setClientHints(boolean clientHints) { this.clientHints = clientHints; return this; @@ -509,6 +522,7 @@ public Builder from(Configuration other) { this.longUrlSignature = other.longUrlSignature; this.signatureAlgorithm = other.signatureAlgorithm; this.oauthToken = other.oauthToken; + this.analytics = other.analytics; return this; } } diff --git a/cloudinary-core/src/main/java/com/cloudinary/Url.java b/cloudinary-core/src/main/java/com/cloudinary/Url.java index 7862d0b4..d02d5a07 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Url.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Url.java @@ -13,7 +13,7 @@ import java.util.regex.Pattern; import java.util.zip.CRC32; -import com.cloudinary.utils.AnalyticsUtils; +import com.cloudinary.utils.Analytics; import com.cloudinary.utils.Base64Coder; import com.cloudinary.utils.ObjectUtils; import com.cloudinary.utils.StringUtils; @@ -409,6 +409,7 @@ public String generate(String source) { String join = StringUtils.join(new String[]{prefix, finalResourceType, signature, transformationStr, version, source}, "/"); String url = StringUtils.mergeSlashesInUrl(join); + if (signUrl && authToken != null && !authToken.equals(AuthToken.NULL_AUTH_TOKEN)) { try { URL tempUrl = new URL(url); @@ -418,9 +419,14 @@ public String generate(String source) { } catch (MalformedURLException ignored) { } } - if (AnalyticsUtils.token != null) { - if(!AnalyticsUtils.checkIfQueryParamExist(url)) { - url = (new StringBuilder()).append(url).append(AnalyticsUtils.analyticsPrefix).append(AnalyticsUtils.token).toString(); + if (cloudinary.analytics != null && cloudinary.config.analytics) { + try { + URL tempUrl = new URL(url); + if (tempUrl.getQuery() == null) { + String path = tempUrl.getPath(); + url = url + "?" + cloudinary.analytics.toQueryParam(); + } + } catch (MalformedURLException ignored) { } } return url; diff --git a/cloudinary-core/src/main/java/com/cloudinary/utils/Analytics.java b/cloudinary-core/src/main/java/com/cloudinary/utils/Analytics.java new file mode 100644 index 00000000..e81ec716 --- /dev/null +++ b/cloudinary-core/src/main/java/com/cloudinary/utils/Analytics.java @@ -0,0 +1,113 @@ +package com.cloudinary.utils; + +import java.util.Arrays; +import java.util.List; + +public class Analytics { + private String sdkTokenQueryKey = "_a="; //sdkTokenQueryKey + public String algoVersion = "A"; + public String SDKCode = ""; // Java = G, Android = F + public String SDKSemver = ""; // Calculate the SDK version . + public String techVersion = ""; // Calculate the Java version. + public void Analytics() { + // initilaize with Java values. + // From Android pick the values. + } + + public Analytics() {} + public Analytics(String sdkCode, String sdkVersion, String techVersion) { + this.SDKCode = sdkCode; + this.SDKSemver = sdkVersion; + this.techVersion = techVersion; + } + + public Analytics setSDKCode(String SDKCode) { + this.SDKCode = SDKCode; + return this; + } + + public Analytics setSDKSemver(String SDKSemver) { + this.SDKSemver = SDKSemver; + return this; + } + + public Analytics setTechVersion(String techVersion) { + this.techVersion = techVersion; + return this; + } + + /** + * Function turn analytics variables into viable query parameter. + * @return query param with analytics values. + */ + public String toQueryParam() { + try { + return sdkTokenQueryKey + getAlgorithmVersion() + getSDKType() + getSDKVersion() + getTechVersion() + getSDKFeatureCode(); + } catch (Exception e) { + return sdkTokenQueryKey + "E"; + } + } + + private String getTechVersion() throws Exception { + String[] techVersionString = techVersion.split("_"); + String[] versions = techVersionString[0].split("\\."); + if (versions.length > 2) { + versions = Arrays.copyOf(versions, versions.length - 1); + } + return getPaddedString(StringUtils.join(versions, ".")); + } + + private String getSDKType() { + return SDKCode; + } + + private String getAlgorithmVersion() { + return "A"; + } + + private String getSDKFeatureCode() { + return "0"; + } + + private String getSDKVersion() throws Exception { + return getPaddedString(SDKSemver); + } + + private String getPaddedString(String string) throws Exception { + String paddedReversedSemver = ""; + int parts = string.split("\\.").length; + int paddedStringLength = parts * 6; + try { + paddedReversedSemver = reverseVersion(string); + } catch (Exception e) { + throw new Exception("Error"); + } + int num = Integer.parseInt(StringUtils.join(paddedReversedSemver.split("\\."),"")); + + String paddedBinary = StringUtils.padStart(Integer.toBinaryString(num), paddedStringLength, '0'); + + if (paddedBinary.length() % 6 != 0) { + throw new Exception("Error"); + } + + String result = ""; + List resultList = StringUtils.usingPattern(paddedBinary,6); + int i = 0; + while (i < resultList.size()) { + result = result + Base64Map.values.get(resultList.get(i)); + i++; + } + return result; + } + + private String reverseVersion(String SDKSemver) throws Exception { + if (SDKSemver.split("\\.").length < 2) { + throw new Exception("invalid semVer, must have at least two segments"); + } + String[] versionArray = SDKSemver.split("\\."); + for (int i = 0 ; i < versionArray.length; i ++) { + versionArray[i] = StringUtils.padStart(versionArray[i], 2, '0'); + } + return StringUtils.join(StringUtils.reverseStringArray(versionArray), "."); + } +} \ No newline at end of file diff --git a/cloudinary-core/src/main/java/com/cloudinary/utils/AnalyticsUtils.java b/cloudinary-core/src/main/java/com/cloudinary/utils/AnalyticsUtils.java deleted file mode 100644 index c055dc96..00000000 --- a/cloudinary-core/src/main/java/com/cloudinary/utils/AnalyticsUtils.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.cloudinary.utils; - -import java.net.MalformedURLException; -import java.net.URL; - -public class AnalyticsUtils { - public static String analyticsPrefix = "?_a="; - public static String token = null; - - public static Boolean checkIfQueryParamExist(String urlString) { - try { - URL url = new URL(urlString); - if (url.getQuery() == null) { - return false; - } - } catch (MalformedURLException e) { - return true; - } - return true; - } -} diff --git a/cloudinary-core/src/main/java/com/cloudinary/utils/Base64Map.java b/cloudinary-core/src/main/java/com/cloudinary/utils/Base64Map.java new file mode 100644 index 00000000..d5e755f9 --- /dev/null +++ b/cloudinary-core/src/main/java/com/cloudinary/utils/Base64Map.java @@ -0,0 +1,76 @@ +package com.cloudinary.utils; + +import java.util.HashMap; +import java.util.Map; + +public class Base64Map { + public static Map values; + + static { + values = new HashMap<>(); + values.put("000000", "A"); + values.put("000001", "B"); + values.put("000010", "C"); + values.put("000011", "D"); + values.put("000100", "E"); + values.put("000101", "F"); + values.put("000110", "G"); + values.put("000111", "H"); + values.put("001000", "I"); + values.put("001001", "J"); + values.put("001010", "K"); + values.put("001011", "L"); + values.put("001100", "M"); + values.put("001101", "N"); + values.put("001110", "O"); + values.put("001111", "P"); + values.put("010000", "Q"); + values.put("010001", "R"); + values.put("010010", "S"); + values.put("010011", "T"); + values.put("010100", "U"); + values.put("010101", "V"); + values.put("010110", "W"); + values.put("010111", "X"); + values.put("011000", "Y"); + values.put("011001", "Z"); + values.put("011010", "a"); + values.put("011011", "b"); + values.put("011100", "c"); + values.put("011101", "d"); + values.put("011110", "e"); + values.put("011111", "f"); + values.put("100000","g"); + values.put("100001","h"); + values.put("100010","i"); + values.put("100011","j"); + values.put("100100","k"); + values.put("100101","l"); + values.put("100110","m"); + values.put("100111","n"); + values.put("101000","o"); + values.put("101001","p"); + values.put("101010","q"); + values.put("101011","r"); + values.put("101100","s"); + values.put("101101","t"); + values.put("101110","u"); + values.put("101111","v"); + values.put("110000","w"); + values.put("110001","x"); + values.put("110010","y"); + values.put("110011","z"); + values.put("110100","0"); + values.put("110101","1"); + values.put("110110","2"); + values.put("110111","3"); + values.put("111000","4"); + values.put("111001","5"); + values.put("111010","6"); + values.put("111011","7"); + values.put("111100","8"); + values.put("111101","9"); + values.put("111110","+"); + values.put("111111","/"); + } +} diff --git a/cloudinary-core/src/main/java/com/cloudinary/utils/StringUtils.java b/cloudinary-core/src/main/java/com/cloudinary/utils/StringUtils.java index 3149e018..2388ed0d 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/utils/StringUtils.java +++ b/cloudinary-core/src/main/java/com/cloudinary/utils/StringUtils.java @@ -4,8 +4,7 @@ import java.io.IOException; import java.io.InputStream; import java.nio.charset.Charset; -import java.util.Collection; -import java.util.List; +import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -216,7 +215,7 @@ public static boolean isRemoteUrl(String file) { * Replaces the unsafe characters in url with url-encoded values. * This is based on {@link java.net.URLEncoder#encode(String, String)} * @param url The url to encode - * @param unsafe Regex pattern of unsafe caracters + * @param unsafe Regex pattern of unsafe characters * @param charset * @return An encoded url string */ @@ -397,4 +396,55 @@ public static String mergeSlashesInUrl(String url) { public static String emptyIfNull(String str) { return isEmpty(str) ? "" : str; } + + /** + * Returns an array of strings in reveresed order. + * + * @param strings array of strings + * @return reversed array of string or empty array, if the passed array is null or empty + */ + static String[] reverseStringArray(String[] strings) { + Collections.reverse(Arrays.asList(strings)); + return strings; + } + + /** + * Returns the padded string with requested character to the left with length equals to length param sent. + * + * @param inputString The string to process + * @param length The requested length to pad to + * @param paddingCharacter The requested character to pad with + * @return reversed array of string or empty array, if the passed array is null or empty + */ + public static String padStart(String inputString, int length, char paddingCharacter) { + if (inputString.length() >= length) { + return inputString; + } + StringBuilder sb = new StringBuilder(); + while (sb.length() < length - inputString.length()) { + sb.append(paddingCharacter); + } + sb.append(inputString); + + return sb.toString(); + } + + /** + * Break string into groups of n size strings + * + * @param text The string to process + * @param n Size of group + * @return List with all strings with group size n. + */ + public static List usingPattern(String text, int n) { + List results = new ArrayList<>(); + + Pattern pattern = Pattern.compile(".{1," + n + "}"); + Matcher matcher = pattern.matcher(text); + while (matcher.find()) { + String match = text.substring(matcher.start(), matcher.end()); + results.add(match); + } + return results; + } } diff --git a/cloudinary-core/src/test/java/com/cloudinary/AuthTokenTest.java b/cloudinary-core/src/test/java/com/cloudinary/AuthTokenTest.java index f97e2e88..b93f21b6 100644 --- a/cloudinary-core/src/test/java/com/cloudinary/AuthTokenTest.java +++ b/cloudinary-core/src/test/java/com/cloudinary/AuthTokenTest.java @@ -1,6 +1,6 @@ package com.cloudinary; -import com.cloudinary.utils.AnalyticsUtils; +import com.cloudinary.utils.Analytics; import org.hamcrest.Matchers; import org.junit.Before; import org.junit.Rule; @@ -95,10 +95,11 @@ public void testAuthenticatedUrl() { @Test public void testUrlAnalyticsWithQueryParams() { + cloudinary.config.analytics = true; + cloudinary.setAnalytics(new Analytics("F", "2.0.0", System.getProperty("java.version"))); cloudinary.config.privateCdn = true; String url = cloudinary.url().signed(true).type("authenticated").generate("test"); assertEquals(url,"http://test123-res.cloudinary.com/image/authenticated/test?__cld_token__=st=11111111~exp=11111411~hmac=735a49389a72ac0b90d1a84ac5d43facd1a9047f153b39e914747ef6ed195e53"); - AnalyticsUtils.token = null; cloudinary.config.privateCdn = false; } diff --git a/cloudinary-core/src/test/java/com/cloudinary/analytics/AnalyticsTest.java b/cloudinary-core/src/test/java/com/cloudinary/analytics/AnalyticsTest.java new file mode 100644 index 00000000..84dd599b --- /dev/null +++ b/cloudinary-core/src/test/java/com/cloudinary/analytics/AnalyticsTest.java @@ -0,0 +1,93 @@ +package com.cloudinary.analytics; + +import com.cloudinary.Cloudinary; +import com.cloudinary.utils.Analytics; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TestName; + +public class AnalyticsTest { + + private Cloudinary cloudinary; + + @Rule + public TestName currentTest = new TestName(); + + @Before + public void setUp() { + System.out.println("Running " + this.getClass().getName() + "." + currentTest.getMethodName()); + this.cloudinary = new Cloudinary("cloudinary://a:b@test123?load_strategies=false"); + } + + @Test + public void testToQueryParam() { + Analytics analytics = new Analytics("F", "2.0.0", "1.8.0"); + String result = analytics.toQueryParam(); + Assert.assertEquals(result, "_a=AFAACMh0"); + } + + @Test + public void testUrlWithAnalytics() { + cloudinary.config.analytics = true; + cloudinary.setAnalytics(new Analytics("F", "2.0.0", "1.8.0")); + String url = cloudinary.url().generate("test"); + Assert.assertEquals(url, "http://res.cloudinary.com/test123/image/upload/test?_a=AFAACMh0"); + cloudinary.config.analytics = false; + cloudinary.analytics = null; + } + + @Test + public void testUrlWithNoAnalytics() { + String url = cloudinary.url().generate("test"); + Assert.assertEquals(url, "http://res.cloudinary.com/test123/image/upload/test"); + cloudinary.config.analytics = false; + cloudinary.analytics = null; + } + + @Test + public void testUrlWithNoAnalyticsDefined() { + cloudinary.config.analytics = false; + String url = cloudinary.url().generate("test"); + Assert.assertEquals(url, "http://res.cloudinary.com/test123/image/upload/test"); + cloudinary.config.analytics = false; + cloudinary.analytics = null; + } + + @Test + public void testUrlWithNoAnalyticsNull() { + cloudinary.analytics = null; + String url = cloudinary.url().generate("test"); + Assert.assertEquals(url, "http://res.cloudinary.com/test123/image/upload/test"); + cloudinary.config.analytics = false; + cloudinary.analytics = null; + } + + @Test + public void testUrlWithNoAnalyticsNullAndTrue() { + cloudinary.config.analytics = true; + cloudinary.analytics = null; + String url = cloudinary.url().generate("test"); + Assert.assertEquals(url, "http://res.cloudinary.com/test123/image/upload/test"); + cloudinary.config.analytics = false; + cloudinary.analytics = null; + } + + @Test + public void testMiscAnalyticsObject() { + cloudinary.config.analytics = true; + Analytics analytics = new Analytics("Z", "1.24.0", "12.0.0"); + String result = analytics.toQueryParam(); + Assert.assertEquals(result, "_a=AZAlhAM0"); + } + + @Test + public void testErrorAnalytics() { + cloudinary.config.analytics = true; + Analytics analytics = new Analytics("Z", "1.24.0", "0"); + String result = analytics.toQueryParam(); + Assert.assertEquals(result, "_a=E"); + } + +} \ No newline at end of file diff --git a/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java b/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java index 15cb52d7..109b44ed 100644 --- a/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java +++ b/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java @@ -2,7 +2,6 @@ import com.cloudinary.*; import com.cloudinary.transformation.*; -import com.cloudinary.utils.AnalyticsUtils; import com.cloudinary.utils.ObjectUtils; import junitparams.JUnitParamsRunner; import junitparams.Parameters; @@ -1455,21 +1454,4 @@ private void setRandomValue(Random rand, Field field, Object instance) throws Il private > T randomEnum(Class clazz, Random random) { return clazz.getEnumConstants()[random.nextInt(clazz.getEnumConstants().length)]; } - - @Test - public void testUrlWithAnalytics() { - AnalyticsUtils.token = "AFAACAI0"; - String url = cloudinary.url().generate("test"); - assertEquals(url,"http://res.cloudinary.com/test123/image/upload/test?_a=AFAACAI0"); - AnalyticsUtils.token = null; - } - - @Test - public void testUrlWithNoAnalytics() { - AnalyticsUtils.token = null; - String url = cloudinary.url().generate("test"); - assertEquals(url,"http://res.cloudinary.com/test123/image/upload/test"); - } - - } diff --git a/java_shared.gradle b/java_shared.gradle index 134636f7..f61e3fea 100644 --- a/java_shared.gradle +++ b/java_shared.gradle @@ -2,6 +2,7 @@ sourceCompatibility = 1.7 targetCompatibility = 1.7 javadoc { + failOnError false options.encoding = 'UTF-8' } From 39e45d4a4d9c75918dfab4a9c60a2a964bd490ca Mon Sep 17 00:00:00 2001 From: adimiz1 Date: Mon, 31 Jan 2022 08:48:37 +0200 Subject: [PATCH 025/150] Add Analytics support --- .../main/java/com/cloudinary/Cloudinary.java | 4 ++-- .../java/com/cloudinary/utils/Analytics.java | 9 ++++---- .../com/cloudinary/utils/StringUtils.java | 2 +- .../cloudinary/analytics/AnalyticsTest.java | 21 +++++++------------ 4 files changed, 15 insertions(+), 21 deletions(-) diff --git a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java index 8b0b462a..0bda8649 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java @@ -155,9 +155,9 @@ public void setUserAgent(String prefix, String version){ } /** - * Set the prefix and version for the user agent that will be sent with every API call + * Set the analytics object that will be sent with every URL generation call. * a userAgent is built from `prefix/version (additional data)` - * @param analytics - the analytics objec to set + * @param analytics - the analytics object to set */ public void setAnalytics(Analytics analytics) { this.analytics = analytics; diff --git a/cloudinary-core/src/main/java/com/cloudinary/utils/Analytics.java b/cloudinary-core/src/main/java/com/cloudinary/utils/Analytics.java index e81ec716..1a057e78 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/utils/Analytics.java +++ b/cloudinary-core/src/main/java/com/cloudinary/utils/Analytics.java @@ -4,7 +4,8 @@ import java.util.List; public class Analytics { - private String sdkTokenQueryKey = "_a="; //sdkTokenQueryKey + private String sdkTokenQueryKey = "_a"; //sdkTokenQueryKey + private String sdkQueryDelimiter = "="; public String algoVersion = "A"; public String SDKCode = ""; // Java = G, Android = F public String SDKSemver = ""; // Calculate the SDK version . @@ -42,9 +43,9 @@ public Analytics setTechVersion(String techVersion) { */ public String toQueryParam() { try { - return sdkTokenQueryKey + getAlgorithmVersion() + getSDKType() + getSDKVersion() + getTechVersion() + getSDKFeatureCode(); + return sdkTokenQueryKey + sdkQueryDelimiter + getAlgorithmVersion() + getSDKType() + getSDKVersion() + getTechVersion() + getSDKFeatureCode(); } catch (Exception e) { - return sdkTokenQueryKey + "E"; + return sdkTokenQueryKey + sdkQueryDelimiter + "E"; } } @@ -91,7 +92,7 @@ private String getPaddedString(String string) throws Exception { } String result = ""; - List resultList = StringUtils.usingPattern(paddedBinary,6); + List resultList = StringUtils.getAllSubStringWithSize(paddedBinary,6); int i = 0; while (i < resultList.size()) { result = result + Base64Map.values.get(resultList.get(i)); diff --git a/cloudinary-core/src/main/java/com/cloudinary/utils/StringUtils.java b/cloudinary-core/src/main/java/com/cloudinary/utils/StringUtils.java index 2388ed0d..6dcbc664 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/utils/StringUtils.java +++ b/cloudinary-core/src/main/java/com/cloudinary/utils/StringUtils.java @@ -436,7 +436,7 @@ public static String padStart(String inputString, int length, char paddingCharac * @param n Size of group * @return List with all strings with group size n. */ - public static List usingPattern(String text, int n) { + public static List getAllSubStringWithSize(String text, int n) { List results = new ArrayList<>(); Pattern pattern = Pattern.compile(".{1," + n + "}"); diff --git a/cloudinary-core/src/test/java/com/cloudinary/analytics/AnalyticsTest.java b/cloudinary-core/src/test/java/com/cloudinary/analytics/AnalyticsTest.java index 84dd599b..dd2ef998 100644 --- a/cloudinary-core/src/test/java/com/cloudinary/analytics/AnalyticsTest.java +++ b/cloudinary-core/src/test/java/com/cloudinary/analytics/AnalyticsTest.java @@ -2,10 +2,7 @@ import com.cloudinary.Cloudinary; import com.cloudinary.utils.Analytics; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; +import org.junit.*; import org.junit.rules.TestName; public class AnalyticsTest { @@ -34,16 +31,12 @@ public void testUrlWithAnalytics() { cloudinary.setAnalytics(new Analytics("F", "2.0.0", "1.8.0")); String url = cloudinary.url().generate("test"); Assert.assertEquals(url, "http://res.cloudinary.com/test123/image/upload/test?_a=AFAACMh0"); - cloudinary.config.analytics = false; - cloudinary.analytics = null; } @Test public void testUrlWithNoAnalytics() { String url = cloudinary.url().generate("test"); Assert.assertEquals(url, "http://res.cloudinary.com/test123/image/upload/test"); - cloudinary.config.analytics = false; - cloudinary.analytics = null; } @Test @@ -51,8 +44,6 @@ public void testUrlWithNoAnalyticsDefined() { cloudinary.config.analytics = false; String url = cloudinary.url().generate("test"); Assert.assertEquals(url, "http://res.cloudinary.com/test123/image/upload/test"); - cloudinary.config.analytics = false; - cloudinary.analytics = null; } @Test @@ -60,8 +51,6 @@ public void testUrlWithNoAnalyticsNull() { cloudinary.analytics = null; String url = cloudinary.url().generate("test"); Assert.assertEquals(url, "http://res.cloudinary.com/test123/image/upload/test"); - cloudinary.config.analytics = false; - cloudinary.analytics = null; } @Test @@ -70,8 +59,6 @@ public void testUrlWithNoAnalyticsNullAndTrue() { cloudinary.analytics = null; String url = cloudinary.url().generate("test"); Assert.assertEquals(url, "http://res.cloudinary.com/test123/image/upload/test"); - cloudinary.config.analytics = false; - cloudinary.analytics = null; } @Test @@ -90,4 +77,10 @@ public void testErrorAnalytics() { Assert.assertEquals(result, "_a=E"); } + @After + public void tearDown() { + cloudinary.config.analytics = false; + cloudinary.analytics = null; + } + } \ No newline at end of file From 2fe233ac62e3cdc4d6a6b14fbff3db72004e5df8 Mon Sep 17 00:00:00 2001 From: adimiz1 Date: Mon, 31 Jan 2022 09:38:46 +0200 Subject: [PATCH 026/150] Update README.md --- README.md | 190 +++++++++++++++++------------------------------------- 1 file changed, 58 insertions(+), 132 deletions(-) diff --git a/README.md b/README.md index ac8d9ee5..3a5afcb4 100644 --- a/README.md +++ b/README.md @@ -1,34 +1,36 @@ [![Build Status](https://travis-ci.org/cloudinary/cloudinary_java.svg?branch=master)](https://travis-ci.org/cloudinary/cloudinary_java) -[![Maven Central](https://img.shields.io/maven-central/v/com.cloudinary/cloudinary-core.svg)](http://search.maven.org/#search%7Cga%7C1%7Cg%3Acom.cloudinary) -[![license](https://img.shields.io/github/license/cloudinary/cloudinary_js.svg?maxAge=2592000)]() Cloudinary ========== -Cloudinary is a cloud service that offers a solution to a web application's entire image management pipeline. +## About +The Cloudinary Java SDK allows you to quickly and easily integrate your application with Cloudinary. +Effortlessly optimize and transform your cloud's assets. -Easily upload images to the cloud. Automatically perform smart image resizing, cropping and conversion without installing any complex software. -Integrate Facebook or Twitter profile image extraction in a snap, in any dimension and style to match your website’s graphics requirements. -Images are seamlessly delivered through a fast CDN, and much much more. +### Additional documentation +This Readme provides basic installation and usage information. +For the complete documentation, see the [Java SDK Guide](https://cloudinary.com/documentation/java_integration). -Cloudinary offers comprehensive APIs and administration capabilities and is easy to integrate with any web application, existing or new. +## Table of Contents +- [Key Features](#key-features) +- [Version Support](#Version-Support) +- [Installation](#installation) +- [Usage](#usage) + - [Setup](#Setup) + - [Transform and Optimize Assets](#Transform-and-Optimize-Assets) + - [File upload](#File upload) +## Key Features +- [Transform](https://cloudinary.com/documentation/java_video_manipulation) and [optimize](https://cloudinary.com/documentation/java_image_manipulation#image_optimizations) assets (links to docs). +- [Upload assets to cloud](https://cloudinary.com/documentation/java_image_and_video_upload) -Cloudinary provides URL and HTTP based APIs that can be easily integrated with any Web development framework. +## Version Support +| SDK Version | Java 6+ | +|----------------|---------| +| 1.1.0 - 1.29.0 | V | -For Java, Cloudinary provides a library for simplifying the integration even further. - -**Notes:** - -* There are three flavors of the library to support different HttpClient versions: cloudinary-http42, cloudinary-http43 and cloudinary-http44. -* For Android there's a separate library available at https://github.com/cloudinary/cloudinary_android - -## Getting started guide -![](https://res.cloudinary.com/cloudinary/image/upload/see_more_bullet.png) **Take a look at our [Getting started guide for Java](https://cloudinary.com/documentation/java_integration#getting_started_guide)**. - -## Setup ###################################################################### - -The cloudinary_java library is available in [Maven Central](https://repo1.maven.org/maven2/com/cloudinary/). To use it, add the following dependency to your pom.xml : +## Installation +The cloudinary_java library is available in [Maven Central](https://mvnrepository.com/artifact/com.cloudinary/cloudinary-core). To use it, add the following dependency to your pom.xml : ```xml @@ -41,52 +43,17 @@ The cloudinary_java library is available in [Maven Central](https://repo1.maven. Alternatively, download cloudinary_java from [here](https://repo1.maven.org/maven2/com/cloudinary/cloudinary-core/1.29.0/cloudinary-core-1.29.0.jar) and [here](https://repo1.maven.org/maven2/com/cloudinary/cloudinary-http44/1.29.0/cloudinary-http44-1.29.0.jar) and see [build.gradle](https://github.com/cloudinary/cloudinary_java/blob/master/cloudinary-http44/build.gradle) for library dependencies. -## Try it right away - -Sign up for a [free account](https://cloudinary.com/users/register/free) so you can try out image transformations and seamless image delivery through CDN. - -*Note: Replace `demo` in all the following examples with your Cloudinary's `cloud name`.* - -Accessing an uploaded image with the `sample` public ID through a CDN: - - http://res.cloudinary.com/demo/image/upload/sample.jpg - -![Sample](https://res.cloudinary.com/demo/image/upload/w_0.4/sample.jpg "Sample") - -Generating a 150x100 version of the `sample` image and downloading it through a CDN: - - http://res.cloudinary.com/demo/image/upload/w_150,h_100,c_fill/sample.jpg - -![Sample 150x100](https://res.cloudinary.com/demo/image/upload/w_150,h_100,c_fill/sample.jpg "Sample 150x100") - -Converting to a 150x100 PNG with rounded corners of 20 pixels: - - http://res.cloudinary.com/demo/image/upload/w_150,h_100,c_fill,r_20/sample.png - -![Sample 150x150 Rounded PNG](https://res.cloudinary.com/demo/image/upload/w_150,h_100,c_fill,r_20/sample.png "Sample 150x150 Rounded PNG") - -For plenty more transformation options, see our [image transformations documentation](http://cloudinary.com/documentation/image_transformations). - -Generating a 120x90 thumbnail based on automatic face detection of the Facebook profile picture of Bill Clinton: - - http://res.cloudinary.com/demo/image/facebook/c_thumb,g_face,h_90,w_120/billclinton.jpg - -![Facebook 90x120](https://res.cloudinary.com/demo/image/facebook/c_thumb,g_face,h_90,w_120/billclinton.jpg "Facebook 90x200") - -For more details, see our documentation for embedding [Facebook](https://cloudinary.com/documentation/facebook_profile_pictures) and [Twitter](https://cloudinary.com/documentation/twitter_profile_pictures) profile pictures. - ## Usage +### Setup -### Configuration - -Each request for building a URL of a remote cloud resource must have the `cloud_name` parameter set. -Each request to our secure APIs (e.g., image uploads, eager sprite generation) must have the `api_key` and `api_secret` parameters set. +Each request for building a URL of a remote cloud resource must have the `cloud_name` parameter set. +Each request to our secure APIs (e.g., image uploads, eager sprite generation) must have the `api_key` and `api_secret` parameters set. See [API, URLs and access identifiers](https://cloudinary.com/documentation/solution_overview#account_and_api_setup) for more details. -Setting the `cloud_name`, `api_key` and `api_secret` parameters can be done either directly in each call to a Cloudinary method, +Setting the `cloud_name`, `api_key` and `api_secret` parameters can be done either directly in each call to a Cloudinary method, by when initializing the Cloudinary object, or by using the CLOUDINARY_URL environment variable / system property. -The entry point of the library is the Cloudinary object. +The entry point of the library is the Cloudinary object. ```java Cloudinary cloudinary = new Cloudinary(); ``` @@ -105,8 +72,8 @@ Another example of setting the configuration parameters by providing the CLOUDIN Cloudinary cloudinary = new Cloudinary("cloudinary://123456789012345:abcdeghijklmnopqrstuvwxyz12@n07t21i7"); -### Embedding and transforming images - +### Transform and Optimize Assets +- [See full documentation](https://cloudinary.com/documentation/java_image_manipulation) Any image uploaded to Cloudinary can be transformed and embedded using powerful view helper methods: The following example generates the url for accessing an uploaded `sample` image while transforming it to fill a 100x150 rectangle: @@ -115,38 +82,29 @@ The following example generates the url for accessing an uploaded `sample` image cloudinary.url().transformation(new Transformation().width(100).height(150).crop("fill")).generate("sample.jpg"); ``` -Another example, emedding a smaller version of an uploaded image while generating a 90x90 face detection based thumbnail: +Another example, emedding a smaller version of an uploaded image while generating a 90x90 face detection based thumbnail: ```java cloudinary.url().transformation(new Transformation().width(90).height(90).crop("thumb").gravity("face")).generate("woman.jpg"); ``` -You can provide either a Facebook name or a numeric ID of a Facebook profile or a fan page. - +You can provide either a Facebook name or a numeric ID of a Facebook profile or a fan page. + Embedding a Facebook profile to match your graphic design is very simple: ```java cloudinary.url().type("facebook").transformation(new Transformation().width(130).height(130).crop("fill").gravity("north_west")).generate("billclinton.jpg"); ``` -Same goes for Twitter: - -```java -cloudinary.url().type("twitter_name").generate("billclinton.jpg"); -``` - -![](https://res.cloudinary.com/cloudinary/image/upload/see_more_bullet.png) **See [our documentation](https://cloudinary.com/documentation/java_image_manipulation) for more information about displaying and transforming images in Java**. - -### Upload - +### File upload Assuming you have your Cloudinary configuration parameters defined (`cloud_name`, `api_key`, `api_secret`), uploading to Cloudinary is very simple. - -The following example uploads a local JPG to the cloud: + +The following example uploads a local JPG to the cloud: ```java cloudinary.uploader().upload("my_picture.jpg", ObjectUtils.emptyMap()); ``` - + The uploaded image is assigned a randomly generated public ID. The image is immediately available for download through a CDN: ```java @@ -155,7 +113,7 @@ cloudinary.url().generate("abcfrmo8zul1mafopawefg.jpg"); # http://res.cloudinary.com/demo/image/upload/abcfrmo8zul1mafopawefg.jpg ``` -You can also specify your own public ID: +You can also specify your own public ID: ```java cloudinary.uploader().upload("http://www.example.com/image.jpg", ObjectUtils.asMap("public_id", "sample_remote")); @@ -165,60 +123,28 @@ cloudinary.url().generate("sample_remote.jpg"); # http://res.cloudinary.com/demo/image/upload/sample_remote.jpg ``` -![](https://res.cloudinary.com/cloudinary/image/upload/see_more_bullet.png) **See [our documentation](https://cloudinary.com/documentation/java_image_upload) for plenty more options of uploading to the cloud from your Java code**. - -### imageTag - -Returns an html image tag pointing to Cloudinary. - -Usage: - -```java -cloudinary.url().format("png").transformation(new Transformation().width(100).height(100).crop("fill")).imageTag("sample"); - -# -``` - -### imageUploadTag - -Returns an html input field for direct image upload, to be used in conjunction with [cloudinary\_js package](https://github.com/cloudinary/cloudinary_js/). It integrates [jQuery-File-Upload widget](https://github.com/blueimp/jQuery-File-Upload) and provides all the necessary parameters for a direct upload. - -Usage: - -```java -Map options = ObjectUtils.asMap("resource_type", "auto"); -Map htmlOptions = ObjectUtils.asMap("alt", "sample"); -String html = cloudinary.uploader().imageUploadTag("image_id", options, htmlOptions); -``` - -![](https://res.cloudinary.com/cloudinary/image/upload/see_more_bullet.png) **See [our documentation](https://cloudinary.com/documentation/java_image_upload#direct_uploading_from_the_browser) for plenty more options of uploading directly from the browser**. - -## Additional resources ########################################################## - -Additional resources are available at: - -* [Website](https://cloudinary.com) -* [Interactive demo](https://demo.cloudinary.com/default) -* [Knowledge Base](https://support.cloudinary.com/hc/en-us) -* [Documentation](https://cloudinary.com/documentation) -* [Documentation for Java integration](https://cloudinary.com/documentation/java_integration) -* [Image transformations documentation](https://cloudinary.com/documentation/image_transformations) -* [Upload API documentation](https://cloudinary.com/documentation/upload_images) - -## Support - -You can [open an issue through GitHub](https://github.com/cloudinary/cloudinary_java/issues). - -Contact us [https://cloudinary.com/contact](https://cloudinary.com/contact) - -Stay tuned for updates, tips and tutorials: [Blog](https://cloudinary.com/blog), [Twitter](https://twitter.com/cloudinary), [Facebook](https://www.facebook.com/Cloudinary). - -## Join the Community ########################################################## +![](https://res.cloudinary.com/cloudinary/image/upload/see_more_bullet.png) **See [our documentation](https://cloudinary.com/documentation/java_image_upload) for plenty more options of uploading to the cloud from your Java code**. -Impact the product, hear updates, test drive new features and more! Join [here](https://www.facebook.com/groups/CloudinaryCommunity). +## Contributions +See [contributing guidelines](/CONTRIBUTING.md). +## Get Help +- [Open a Github issue](https://github.com/CloudinaryLtd/cloudinary_java/issues) (for issues related to the SDK) +- [Open a support ticket](https://cloudinary.com/contact) (for issues related to your account) -## License ####################################################################### +## About Cloudinary +Cloudinary is a powerful media API for websites and mobile apps alike, Cloudinary enables developers to efficiently manage, transform, optimize, and deliver images and videos through multiple CDNs. Ultimately, viewers enjoy responsive and personalized visual-media experiencesβ€”irrespective of the viewing device. -Released under the MIT license. +## Additional Resources +- [Cloudinary Transformation and REST API References](https://cloudinary.com/documentation/cloudinary_references): Comprehensive references, including syntax and examples for all SDKs. +- [MediaJams.dev](https://mediajams.dev/): Bite-size use-case tutorials written by and for Cloudinary Developers +- [DevJams](https://www.youtube.com/playlist?list=PL8dVGjLA2oMr09amgERARsZyrOz_sPvqw): Cloudinary developer podcasts on YouTube. +- [Cloudinary Academy](https://training.cloudinary.com/): Free self-paced courses, instructor-led virtual courses, and on-site courses. +- [Code Explorers and Feature Demos](https://cloudinary.com/documentation/code_explorers_demos_index): A one-stop shop for all code explorers, Postman collections, and feature demos found in the docs. +- [Cloudinary Roadmap](https://cloudinary.com/roadmap): Your chance to follow, vote, or suggest what Cloudinary should develop next. +- [Cloudinary Facebook Community](https://www.facebook.com/groups/CloudinaryCommunity): Learn from and offer help to other Cloudinary developers. +- [Cloudinary Account Registration](https://cloudinary.com/users/register/free): Free Cloudinary account registration. +- [Cloudinary Website](https://cloudinary.com) +## Licence +Released under the MIT license. \ No newline at end of file From 8e83b061daf8717ef30c37c1f22db4871b2a6de3 Mon Sep 17 00:00:00 2001 From: adimiz1 Date: Mon, 31 Jan 2022 09:40:32 +0200 Subject: [PATCH 027/150] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3a5afcb4..9992595f 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ For the complete documentation, see the [Java SDK Guide](https://cloudinary.com/ - [Usage](#usage) - [Setup](#Setup) - [Transform and Optimize Assets](#Transform-and-Optimize-Assets) - - [File upload](#File upload) + - [File upload](#File-upload) ## Key Features - [Transform](https://cloudinary.com/documentation/java_video_manipulation) and [optimize](https://cloudinary.com/documentation/java_image_manipulation#image_optimizations) assets (links to docs). From 8d58527bb1c315e17575f3dcbba2acdd922e8c5e Mon Sep 17 00:00:00 2001 From: adimiz1 Date: Mon, 31 Jan 2022 09:41:31 +0200 Subject: [PATCH 028/150] Update README.md --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 9992595f..2380f145 100644 --- a/README.md +++ b/README.md @@ -123,8 +123,6 @@ cloudinary.url().generate("sample_remote.jpg"); # http://res.cloudinary.com/demo/image/upload/sample_remote.jpg ``` -![](https://res.cloudinary.com/cloudinary/image/upload/see_more_bullet.png) **See [our documentation](https://cloudinary.com/documentation/java_image_upload) for plenty more options of uploading to the cloud from your Java code**. - ## Contributions See [contributing guidelines](/CONTRIBUTING.md). From 6f5d5511cbf875159178549652e251d1b7fcdfe6 Mon Sep 17 00:00:00 2001 From: adimiz1 Date: Mon, 31 Jan 2022 23:01:21 +0200 Subject: [PATCH 029/150] Add analytics support. --- .../src/main/java/com/cloudinary/utils/Analytics.java | 2 +- .../src/test/java/com/cloudinary/analytics/AnalyticsTest.java | 3 +-- java_shared.gradle | 3 +-- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/cloudinary-core/src/main/java/com/cloudinary/utils/Analytics.java b/cloudinary-core/src/main/java/com/cloudinary/utils/Analytics.java index 1a057e78..f4d0b6d3 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/utils/Analytics.java +++ b/cloudinary-core/src/main/java/com/cloudinary/utils/Analytics.java @@ -111,4 +111,4 @@ private String reverseVersion(String SDKSemver) throws Exception { } return StringUtils.join(StringUtils.reverseStringArray(versionArray), "."); } -} \ No newline at end of file +} diff --git a/cloudinary-core/src/test/java/com/cloudinary/analytics/AnalyticsTest.java b/cloudinary-core/src/test/java/com/cloudinary/analytics/AnalyticsTest.java index dd2ef998..a6a89ac6 100644 --- a/cloudinary-core/src/test/java/com/cloudinary/analytics/AnalyticsTest.java +++ b/cloudinary-core/src/test/java/com/cloudinary/analytics/AnalyticsTest.java @@ -14,7 +14,6 @@ public class AnalyticsTest { @Before public void setUp() { - System.out.println("Running " + this.getClass().getName() + "." + currentTest.getMethodName()); this.cloudinary = new Cloudinary("cloudinary://a:b@test123?load_strategies=false"); } @@ -83,4 +82,4 @@ public void tearDown() { cloudinary.analytics = null; } -} \ No newline at end of file +} diff --git a/java_shared.gradle b/java_shared.gradle index f61e3fea..d23a49b4 100644 --- a/java_shared.gradle +++ b/java_shared.gradle @@ -2,7 +2,6 @@ sourceCompatibility = 1.7 targetCompatibility = 1.7 javadoc { - failOnError false options.encoding = 'UTF-8' } @@ -39,4 +38,4 @@ tasks.withType(Test) { tasks.withType(JavaCompile) { options.encoding = 'UTF-8' -} \ No newline at end of file +} From 8d0d9fcb2640c641623faf1fc508832fb3a55844 Mon Sep 17 00:00:00 2001 From: adimiz1 Date: Tue, 1 Feb 2022 08:02:33 +0200 Subject: [PATCH 030/150] Add analytics support. --- cloudinary-core/src/main/java/com/cloudinary/Url.java | 1 + 1 file changed, 1 insertion(+) diff --git a/cloudinary-core/src/main/java/com/cloudinary/Url.java b/cloudinary-core/src/main/java/com/cloudinary/Url.java index d02d5a07..01b29df8 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Url.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Url.java @@ -422,6 +422,7 @@ public String generate(String source) { if (cloudinary.analytics != null && cloudinary.config.analytics) { try { URL tempUrl = new URL(url); + // if any other query param already exist on the URL do not add analytics query param. if (tempUrl.getQuery() == null) { String path = tempUrl.getPath(); url = url + "?" + cloudinary.analytics.toQueryParam(); From 28049da66552a6e32ee14acffe0b8795a9fefb8b Mon Sep 17 00:00:00 2001 From: adimiz1 Date: Tue, 1 Feb 2022 08:08:35 +0200 Subject: [PATCH 031/150] Update test name --- cloudinary-core/src/main/java/com/cloudinary/Url.java | 1 - cloudinary-core/src/test/java/com/cloudinary/AuthTokenTest.java | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/cloudinary-core/src/main/java/com/cloudinary/Url.java b/cloudinary-core/src/main/java/com/cloudinary/Url.java index 01b29df8..d7b1cc92 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Url.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Url.java @@ -409,7 +409,6 @@ public String generate(String source) { String join = StringUtils.join(new String[]{prefix, finalResourceType, signature, transformationStr, version, source}, "/"); String url = StringUtils.mergeSlashesInUrl(join); - if (signUrl && authToken != null && !authToken.equals(AuthToken.NULL_AUTH_TOKEN)) { try { URL tempUrl = new URL(url); diff --git a/cloudinary-core/src/test/java/com/cloudinary/AuthTokenTest.java b/cloudinary-core/src/test/java/com/cloudinary/AuthTokenTest.java index b93f21b6..bb8b188b 100644 --- a/cloudinary-core/src/test/java/com/cloudinary/AuthTokenTest.java +++ b/cloudinary-core/src/test/java/com/cloudinary/AuthTokenTest.java @@ -94,7 +94,7 @@ public void testAuthenticatedUrl() { } @Test - public void testUrlAnalyticsWithQueryParams() { + public void testUrlNoAnalyticsWithQueryParams() { cloudinary.config.analytics = true; cloudinary.setAnalytics(new Analytics("F", "2.0.0", System.getProperty("java.version"))); cloudinary.config.privateCdn = true; From cc84ddcc8fdf0eca93ae98c1a1fb6ab38006b4dd Mon Sep 17 00:00:00 2001 From: adimiz1 Date: Tue, 1 Feb 2022 11:03:28 +0200 Subject: [PATCH 032/150] Add encode version tests --- .../cloudinary/analytics/AnalyticsTest.java | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/cloudinary-core/src/test/java/com/cloudinary/analytics/AnalyticsTest.java b/cloudinary-core/src/test/java/com/cloudinary/analytics/AnalyticsTest.java index a6a89ac6..9d0a1a12 100644 --- a/cloudinary-core/src/test/java/com/cloudinary/analytics/AnalyticsTest.java +++ b/cloudinary-core/src/test/java/com/cloudinary/analytics/AnalyticsTest.java @@ -1,12 +1,17 @@ package com.cloudinary.analytics; +import com.cloudinary.AuthToken; import com.cloudinary.Cloudinary; import com.cloudinary.utils.Analytics; import org.junit.*; import org.junit.rules.TestName; +import static org.junit.Assert.assertEquals; + public class AnalyticsTest { + public static final String KEY = "00112233FF99"; + private Cloudinary cloudinary; @Rule @@ -14,9 +19,35 @@ public class AnalyticsTest { @Before public void setUp() { + System.out.println("Running " + this.getClass().getName() + "." + currentTest.getMethodName()); this.cloudinary = new Cloudinary("cloudinary://a:b@test123?load_strategies=false"); } + @Test + public void testEncodeVersion() { + Analytics analytics = new Analytics(); + analytics.setSDKSemver("1.24.0"); + String result = analytics.toQueryParam(); + Assert.assertEquals(result, "_a=AGAlhAN0"); + + analytics.setSDKSemver("12.0"); + result = analytics.toQueryParam(); + Assert.assertEquals(result, "_a=AGAMAN0"); + + analytics.setSDKSemver("43.21.26"); + result = analytics.toQueryParam(); + Assert.assertEquals(result, "_a=AG///AN0"); + + analytics.setSDKSemver("0.0.0"); + result = analytics.toQueryParam(); + Assert.assertEquals(result, "_a=AGAAAAN0"); + + analytics.setSDKSemver("43.21.27"); + result = analytics.toQueryParam(); + Assert.assertEquals(result, "_a=E"); + + } + @Test public void testToQueryParam() { Analytics analytics = new Analytics("F", "2.0.0", "1.8.0"); @@ -76,6 +107,21 @@ public void testErrorAnalytics() { Assert.assertEquals(result, "_a=E"); } + @Test + public void testUrlNoAnalyticsWithQueryParams() { + final AuthToken authToken = new AuthToken(KEY).duration(300); + authToken.startTime(11111111); // start time is set for test purposes + cloudinary.config.authToken = authToken; + cloudinary.config.cloudName = "test123"; + + cloudinary.config.analytics = true; + cloudinary.setAnalytics(new Analytics("F", "2.0.0", System.getProperty("java.version"))); + cloudinary.config.privateCdn = true; + String url = cloudinary.url().signed(true).type("authenticated").generate("test"); + assertEquals(url,"http://test123-res.cloudinary.com/image/authenticated/test?__cld_token__=st=11111111~exp=11111411~hmac=735a49389a72ac0b90d1a84ac5d43facd1a9047f153b39e914747ef6ed195e53"); + cloudinary.config.privateCdn = false; + } + @After public void tearDown() { cloudinary.config.analytics = false; From 025b55636da2286d3b5a0889098276b28b76e945 Mon Sep 17 00:00:00 2001 From: adimiz1 Date: Tue, 1 Feb 2022 11:06:40 +0200 Subject: [PATCH 033/150] Add default Java analytics constructor --- .../src/main/java/com/cloudinary/utils/Analytics.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cloudinary-core/src/main/java/com/cloudinary/utils/Analytics.java b/cloudinary-core/src/main/java/com/cloudinary/utils/Analytics.java index f4d0b6d3..e20ae5fa 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/utils/Analytics.java +++ b/cloudinary-core/src/main/java/com/cloudinary/utils/Analytics.java @@ -1,5 +1,7 @@ package com.cloudinary.utils; +import com.cloudinary.Cloudinary; + import java.util.Arrays; import java.util.List; @@ -10,12 +12,10 @@ public class Analytics { public String SDKCode = ""; // Java = G, Android = F public String SDKSemver = ""; // Calculate the SDK version . public String techVersion = ""; // Calculate the Java version. - public void Analytics() { - // initilaize with Java values. - // From Android pick the values. - } - public Analytics() {} + public Analytics() { + this("G", Cloudinary.VERSION,System.getProperty("java.version")); + } public Analytics(String sdkCode, String sdkVersion, String techVersion) { this.SDKCode = sdkCode; this.SDKSemver = sdkVersion; From aad44ad136a25b49a9df569721cb84dce8342b35 Mon Sep 17 00:00:00 2001 From: adimiz1 Date: Tue, 1 Feb 2022 11:06:51 +0200 Subject: [PATCH 034/150] Remove analytics test --- .../src/test/java/com/cloudinary/AuthTokenTest.java | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/cloudinary-core/src/test/java/com/cloudinary/AuthTokenTest.java b/cloudinary-core/src/test/java/com/cloudinary/AuthTokenTest.java index bb8b188b..800fc581 100644 --- a/cloudinary-core/src/test/java/com/cloudinary/AuthTokenTest.java +++ b/cloudinary-core/src/test/java/com/cloudinary/AuthTokenTest.java @@ -93,16 +93,6 @@ public void testAuthenticatedUrl() { } - @Test - public void testUrlNoAnalyticsWithQueryParams() { - cloudinary.config.analytics = true; - cloudinary.setAnalytics(new Analytics("F", "2.0.0", System.getProperty("java.version"))); - cloudinary.config.privateCdn = true; - String url = cloudinary.url().signed(true).type("authenticated").generate("test"); - assertEquals(url,"http://test123-res.cloudinary.com/image/authenticated/test?__cld_token__=st=11111111~exp=11111411~hmac=735a49389a72ac0b90d1a84ac5d43facd1a9047f153b39e914747ef6ed195e53"); - cloudinary.config.privateCdn = false; - } - @Test public void testConfiguration() { cloudinary = new Cloudinary("cloudinary://a:b@test123?load_strategies=false&auth_token[key]=aabbcc112233&auth_token[duration]=200"); From 5e67b33f4e7903961572650c556aad88e7148e73 Mon Sep 17 00:00:00 2001 From: adimiz1 Date: Tue, 1 Feb 2022 11:07:14 +0200 Subject: [PATCH 035/150] Add default initialization for analytics --- cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java index 0bda8649..c12be7ac 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java @@ -46,7 +46,7 @@ public class Cloudinary { private AbstractUploaderStrategy uploaderStrategy; private AbstractApiStrategy apiStrategy; private String userAgent = USER_AGENT_PREFIX+"/"+ VERSION + " "+USER_AGENT_JAVA_VERSION; - public Analytics analytics; + public Analytics analytics = new Analytics(); public Uploader uploader() { return new Uploader(this, uploaderStrategy); } @@ -156,7 +156,6 @@ public void setUserAgent(String prefix, String version){ /** * Set the analytics object that will be sent with every URL generation call. - * a userAgent is built from `prefix/version (additional data)` * @param analytics - the analytics object to set */ public void setAnalytics(Analytics analytics) { From 4f943dda2db809d304c50c54cdaf6871a045140d Mon Sep 17 00:00:00 2001 From: adimiz1 Date: Tue, 1 Feb 2022 11:07:27 +0200 Subject: [PATCH 036/150] Remove misleading if condition for analytics --- cloudinary-core/src/main/java/com/cloudinary/Url.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cloudinary-core/src/main/java/com/cloudinary/Url.java b/cloudinary-core/src/main/java/com/cloudinary/Url.java index d7b1cc92..c5db667d 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Url.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Url.java @@ -418,7 +418,7 @@ public String generate(String source) { } catch (MalformedURLException ignored) { } } - if (cloudinary.analytics != null && cloudinary.config.analytics) { + if (cloudinary.config.analytics) { try { URL tempUrl = new URL(url); // if any other query param already exist on the URL do not add analytics query param. From a1835ebee171dca5c118ac2ff749bf73ce2146b7 Mon Sep 17 00:00:00 2001 From: adimiz1 Date: Tue, 1 Feb 2022 11:42:51 +0200 Subject: [PATCH 037/150] Fix failing URL test --- cloudinary-core/src/main/java/com/cloudinary/Url.java | 2 +- .../src/test/java/com/cloudinary/analytics/AnalyticsTest.java | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/cloudinary-core/src/main/java/com/cloudinary/Url.java b/cloudinary-core/src/main/java/com/cloudinary/Url.java index c5db667d..b9fb0407 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Url.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Url.java @@ -418,7 +418,7 @@ public String generate(String source) { } catch (MalformedURLException ignored) { } } - if (cloudinary.config.analytics) { + if (cloudinary.config.analytics != null && cloudinary.config.analytics) { try { URL tempUrl = new URL(url); // if any other query param already exist on the URL do not add analytics query param. diff --git a/cloudinary-core/src/test/java/com/cloudinary/analytics/AnalyticsTest.java b/cloudinary-core/src/test/java/com/cloudinary/analytics/AnalyticsTest.java index 9d0a1a12..f6564092 100644 --- a/cloudinary-core/src/test/java/com/cloudinary/analytics/AnalyticsTest.java +++ b/cloudinary-core/src/test/java/com/cloudinary/analytics/AnalyticsTest.java @@ -78,7 +78,6 @@ public void testUrlWithNoAnalyticsDefined() { @Test public void testUrlWithNoAnalyticsNull() { - cloudinary.analytics = null; String url = cloudinary.url().generate("test"); Assert.assertEquals(url, "http://res.cloudinary.com/test123/image/upload/test"); } @@ -86,9 +85,8 @@ public void testUrlWithNoAnalyticsNull() { @Test public void testUrlWithNoAnalyticsNullAndTrue() { cloudinary.config.analytics = true; - cloudinary.analytics = null; String url = cloudinary.url().generate("test"); - Assert.assertEquals(url, "http://res.cloudinary.com/test123/image/upload/test"); + Assert.assertEquals(url, "http://res.cloudinary.com/test123/image/upload/test?_a=AGAtVAN0"); } @Test From e463570832ffe904589874144f58aebb6fb84c4a Mon Sep 17 00:00:00 2001 From: adimiz1 Date: Tue, 1 Feb 2022 12:30:59 +0200 Subject: [PATCH 038/150] Fix failing test hardcoded Java version --- .../java/com/cloudinary/analytics/AnalyticsTest.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/cloudinary-core/src/test/java/com/cloudinary/analytics/AnalyticsTest.java b/cloudinary-core/src/test/java/com/cloudinary/analytics/AnalyticsTest.java index f6564092..7e71db52 100644 --- a/cloudinary-core/src/test/java/com/cloudinary/analytics/AnalyticsTest.java +++ b/cloudinary-core/src/test/java/com/cloudinary/analytics/AnalyticsTest.java @@ -27,20 +27,21 @@ public void setUp() { public void testEncodeVersion() { Analytics analytics = new Analytics(); analytics.setSDKSemver("1.24.0"); + analytics.setTechVersion("12.0.0"); String result = analytics.toQueryParam(); - Assert.assertEquals(result, "_a=AGAlhAN0"); + Assert.assertEquals(result, "_a=AGAlhAM0"); analytics.setSDKSemver("12.0"); result = analytics.toQueryParam(); - Assert.assertEquals(result, "_a=AGAMAN0"); + Assert.assertEquals(result, "_a=AGAMAM0"); analytics.setSDKSemver("43.21.26"); result = analytics.toQueryParam(); - Assert.assertEquals(result, "_a=AG///AN0"); + Assert.assertEquals(result, "_a=AG///AM0"); analytics.setSDKSemver("0.0.0"); result = analytics.toQueryParam(); - Assert.assertEquals(result, "_a=AGAAAAN0"); + Assert.assertEquals(result, "_a=AGAAAAM0"); analytics.setSDKSemver("43.21.27"); result = analytics.toQueryParam(); @@ -85,8 +86,9 @@ public void testUrlWithNoAnalyticsNull() { @Test public void testUrlWithNoAnalyticsNullAndTrue() { cloudinary.config.analytics = true; + cloudinary.analytics.setTechVersion("12.0.0"); String url = cloudinary.url().generate("test"); - Assert.assertEquals(url, "http://res.cloudinary.com/test123/image/upload/test?_a=AGAtVAN0"); + Assert.assertEquals(url, "http://res.cloudinary.com/test123/image/upload/test?_a=AGAtVAM0"); } @Test From 8ba890d8646183744fdfc86fd880a1ad2079ccd4 Mon Sep 17 00:00:00 2001 From: adimiz1 Date: Wed, 2 Feb 2022 09:32:43 +0200 Subject: [PATCH 039/150] Version 1.30.0 --- .gitignore | 7 +++++++ CHANGELOG.md | 9 +++++++++ README.md | 8 ++++---- .../src/main/java/com/cloudinary/Cloudinary.java | 2 +- gradle.properties | 2 +- 5 files changed, 22 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index 8c7d1af1..e732dc7e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +## Apple storage files +*.DS_Store + ## Android default ignore # Built application files *.apk @@ -40,3 +43,7 @@ test-output/ appengine-web.xml cloudinary-android/src/androidTest/AndroidManifest.xml +##Tools +/tools/cloudinary_url.txt +/tools/History.md + diff --git a/CHANGELOG.md b/CHANGELOG.md index 0350cb4c..98db5a9a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,13 @@ +1.30.0 / 2022-02-02 +=================== + +Other Changes +------------- + * Update `README.md` + * Add feature `SDK analytics` + * Fix a bug where a publicId which contains 'v[num]' is considered to contain a version, therefore the version is skipped. (#242) + 1.29.0 / 2021-02-10 =================== diff --git a/README.md b/README.md index 2380f145..08c54813 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ For the complete documentation, see the [Java SDK Guide](https://cloudinary.com/ ## Version Support | SDK Version | Java 6+ | |----------------|---------| -| 1.1.0 - 1.29.0 | V | +| 1.1.0 - 1.30.0 | V | ## Installation The cloudinary_java library is available in [Maven Central](https://mvnrepository.com/artifact/com.cloudinary/cloudinary-core). To use it, add the following dependency to your pom.xml : @@ -36,11 +36,11 @@ The cloudinary_java library is available in [Maven Central](https://mvnrepositor com.cloudinary cloudinary-http44 - 1.29.0 + 1.30.0 ``` -Alternatively, download cloudinary_java from [here](https://repo1.maven.org/maven2/com/cloudinary/cloudinary-core/1.29.0/cloudinary-core-1.29.0.jar) and [here](https://repo1.maven.org/maven2/com/cloudinary/cloudinary-http44/1.29.0/cloudinary-http44-1.29.0.jar) +Alternatively, download cloudinary_java from [here](https://repo1.maven.org/maven2/com/cloudinary/cloudinary-core/1.30.0/cloudinary-core-1.30.0.jar) and [here](https://repo1.maven.org/maven2/com/cloudinary/cloudinary-http44/1.30.0/cloudinary-http44-1.30.0.jar) and see [build.gradle](https://github.com/cloudinary/cloudinary_java/blob/master/cloudinary-http44/build.gradle) for library dependencies. ## Usage @@ -145,4 +145,4 @@ Cloudinary is a powerful media API for websites and mobile apps alike, Cloudinar - [Cloudinary Website](https://cloudinary.com) ## Licence -Released under the MIT license. \ No newline at end of file +Released under the MIT license. diff --git a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java index c12be7ac..64e0c45b 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java @@ -38,7 +38,7 @@ public class Cloudinary { public final static String AKAMAI_SHARED_CDN = "res.cloudinary.com"; public final static String SHARED_CDN = AKAMAI_SHARED_CDN; - public final static String VERSION = "1.29.0"; + public final static String VERSION = "1.30.0"; static String USER_AGENT_PREFIX = "CloudinaryJava"; public final static String USER_AGENT_JAVA_VERSION = "(Java " + System.getProperty("java.version") + ")"; diff --git a/gradle.properties b/gradle.properties index ef9fd370..1c79d617 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,7 +13,7 @@ developerEmail=info@cloudinary.com # These two properties must use these exact names to be compatible with 'gradle install' plugin. group=com.cloudinary -version=1.29.0 +version=1.30.0 gnsp.disableApplyOnlyOnRootProjectEnforcement=true From 7d154a964447973aa902e89fe6693b12db40bf44 Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Wed, 2 Feb 2022 11:53:31 +0200 Subject: [PATCH 040/150] Fix analytics test --- .../src/test/java/com/cloudinary/analytics/AnalyticsTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cloudinary-core/src/test/java/com/cloudinary/analytics/AnalyticsTest.java b/cloudinary-core/src/test/java/com/cloudinary/analytics/AnalyticsTest.java index 7e71db52..b45e76e0 100644 --- a/cloudinary-core/src/test/java/com/cloudinary/analytics/AnalyticsTest.java +++ b/cloudinary-core/src/test/java/com/cloudinary/analytics/AnalyticsTest.java @@ -86,9 +86,10 @@ public void testUrlWithNoAnalyticsNull() { @Test public void testUrlWithNoAnalyticsNullAndTrue() { cloudinary.config.analytics = true; + cloudinary.analytics.setSDKSemver("1.30.0"); cloudinary.analytics.setTechVersion("12.0.0"); String url = cloudinary.url().generate("test"); - Assert.assertEquals(url, "http://res.cloudinary.com/test123/image/upload/test?_a=AGAtVAM0"); + Assert.assertEquals(url, "http://res.cloudinary.com/test123/image/upload/test?_a=AGAu5AM0"); } @Test From 70a1f87c5aafffb9be8682e26d0ba6e35fd41ade Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Sun, 13 Feb 2022 10:24:18 +0200 Subject: [PATCH 041/150] Add template for PR --- .github/pull_request_template.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 .github/pull_request_template.md diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 00000000..e2509ff5 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,29 @@ +### Brief Summary of Changes + + +#### What does this PR address? +- [ ] GitHub issue (Add reference - #XX) +- [ ] Refactoring +- [ ] New feature +- [ ] Bug fix +- [ ] Adds more tests + +#### Are tests included? +- [ ] Yes +- [ ] No + +#### Reviewer, please note: + + +#### Checklist: + + +- [ ] My code follows the code style of this project. +- [ ] My change requires a change to the documentation. +- [ ] I ran the full test suite before pushing the changes and all the tests pass. From aaac4f3fbe67003617ab1529da832c1f156e8bcb Mon Sep 17 00:00:00 2001 From: Yomes <1785648+YomesInc@users.noreply.github.com> Date: Wed, 16 Feb 2022 12:00:11 +0300 Subject: [PATCH 042/150] Fix named parameters normalization issue --- .../cloudinary/transformation/BaseExpression.java | 2 +- .../cloudinary/transformation/ExpressionTest.java | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/cloudinary-core/src/main/java/com/cloudinary/transformation/BaseExpression.java b/cloudinary-core/src/main/java/com/cloudinary/transformation/BaseExpression.java index 0da9d702..a4ed118c 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/transformation/BaseExpression.java +++ b/cloudinary-core/src/main/java/com/cloudinary/transformation/BaseExpression.java @@ -123,7 +123,7 @@ private static Pattern getPattern() { sb.append(Pattern.quote(op)).append("|"); } sb.deleteCharAt(sb.length() - 1); - sb.append(")(?=[ _])|(? Date: Tue, 22 Feb 2022 12:48:12 +0200 Subject: [PATCH 043/150] Fix single character variable --- .../com/cloudinary/utils/StringUtils.java | 5 +-- .../transformation/VariableTest.java | 42 +++++++++++++++++++ 2 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 cloudinary-core/src/test/java/com/cloudinary/transformation/VariableTest.java diff --git a/cloudinary-core/src/main/java/com/cloudinary/utils/StringUtils.java b/cloudinary-core/src/main/java/com/cloudinary/utils/StringUtils.java index 6dcbc664..66ec38ff 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/utils/StringUtils.java +++ b/cloudinary-core/src/main/java/com/cloudinary/utils/StringUtils.java @@ -277,9 +277,8 @@ public static String mergeToSingleUnderscore(String s) { */ public static boolean isVariable(String s) { if (s == null || - s.length() < 3 || - !s.startsWith("$") || - !Character.isLetter(s.charAt(1))) { + s.length() < 2 || + !s.startsWith("$")) { return false; } diff --git a/cloudinary-core/src/test/java/com/cloudinary/transformation/VariableTest.java b/cloudinary-core/src/test/java/com/cloudinary/transformation/VariableTest.java new file mode 100644 index 00000000..7ab38288 --- /dev/null +++ b/cloudinary-core/src/test/java/com/cloudinary/transformation/VariableTest.java @@ -0,0 +1,42 @@ +package com.cloudinary.transformation; + +import com.cloudinary.Cloudinary; +import com.cloudinary.Transformation; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TestName; + +import static org.junit.Assert.assertEquals; + +public class VariableTest { + + private Cloudinary cloudinary; + + @Rule + public TestName currentTest = new TestName(); + + @Before + public void setUp() { + System.out.println("Running " + this.getClass().getName() + "." + currentTest.getMethodName()); + this.cloudinary = new Cloudinary("cloudinary://a:b@test123?load_strategies=false"); + } + + @Test + public void testSingleCharacterVariable() { + String url = cloudinary.url().transformation(new Transformation().variable("$a","100").chain().height("$a")).generate("sample.jpg"); + assertEquals("http://res.cloudinary.com/test123/image/upload/$a_100/h_$a/sample.jpg", url); + } + + @Test + public void testDollarOnlyAsVariable() { + String url = cloudinary.url().transformation(new Transformation().variable("$","100").chain().height("$")).generate("sample.jpg"); + assertEquals("http://res.cloudinary.com/test123/image/upload/h_$/sample.jpg", url); + } + + @Test + public void testMultipleCharactersVariable() { + String url = cloudinary.url().transformation(new Transformation().variable("$a45","100").chain().height("$a45")).generate("sample.jpg"); + assertEquals("http://res.cloudinary.com/test123/image/upload/$a45_100/h_$a45/sample.jpg", url); + } +} From dac690b689564e6136e571d523851ff9d059318c Mon Sep 17 00:00:00 2001 From: adimiz1 Date: Tue, 22 Feb 2022 12:55:08 +0200 Subject: [PATCH 044/150] Revert "Fix single character variable" This reverts commit e670916eb30db80c45b42bf026b1e2f5127d4b1c. --- .../com/cloudinary/utils/StringUtils.java | 5 ++- .../transformation/VariableTest.java | 42 ------------------- 2 files changed, 3 insertions(+), 44 deletions(-) delete mode 100644 cloudinary-core/src/test/java/com/cloudinary/transformation/VariableTest.java diff --git a/cloudinary-core/src/main/java/com/cloudinary/utils/StringUtils.java b/cloudinary-core/src/main/java/com/cloudinary/utils/StringUtils.java index 66ec38ff..6dcbc664 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/utils/StringUtils.java +++ b/cloudinary-core/src/main/java/com/cloudinary/utils/StringUtils.java @@ -277,8 +277,9 @@ public static String mergeToSingleUnderscore(String s) { */ public static boolean isVariable(String s) { if (s == null || - s.length() < 2 || - !s.startsWith("$")) { + s.length() < 3 || + !s.startsWith("$") || + !Character.isLetter(s.charAt(1))) { return false; } diff --git a/cloudinary-core/src/test/java/com/cloudinary/transformation/VariableTest.java b/cloudinary-core/src/test/java/com/cloudinary/transformation/VariableTest.java deleted file mode 100644 index 7ab38288..00000000 --- a/cloudinary-core/src/test/java/com/cloudinary/transformation/VariableTest.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.cloudinary.transformation; - -import com.cloudinary.Cloudinary; -import com.cloudinary.Transformation; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestName; - -import static org.junit.Assert.assertEquals; - -public class VariableTest { - - private Cloudinary cloudinary; - - @Rule - public TestName currentTest = new TestName(); - - @Before - public void setUp() { - System.out.println("Running " + this.getClass().getName() + "." + currentTest.getMethodName()); - this.cloudinary = new Cloudinary("cloudinary://a:b@test123?load_strategies=false"); - } - - @Test - public void testSingleCharacterVariable() { - String url = cloudinary.url().transformation(new Transformation().variable("$a","100").chain().height("$a")).generate("sample.jpg"); - assertEquals("http://res.cloudinary.com/test123/image/upload/$a_100/h_$a/sample.jpg", url); - } - - @Test - public void testDollarOnlyAsVariable() { - String url = cloudinary.url().transformation(new Transformation().variable("$","100").chain().height("$")).generate("sample.jpg"); - assertEquals("http://res.cloudinary.com/test123/image/upload/h_$/sample.jpg", url); - } - - @Test - public void testMultipleCharactersVariable() { - String url = cloudinary.url().transformation(new Transformation().variable("$a45","100").chain().height("$a45")).generate("sample.jpg"); - assertEquals("http://res.cloudinary.com/test123/image/upload/$a45_100/h_$a45/sample.jpg", url); - } -} From a0ccbc4f674abfdf7aaa3951627c9db275511429 Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Wed, 23 Feb 2022 07:24:24 +0200 Subject: [PATCH 045/150] Add support for single character variable --- .../src/main/java/com/cloudinary/utils/StringUtils.java | 2 +- cloudinary-core/src/test/java/com/cloudinary/UtilTest.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cloudinary-core/src/main/java/com/cloudinary/utils/StringUtils.java b/cloudinary-core/src/main/java/com/cloudinary/utils/StringUtils.java index 6dcbc664..0d25bacb 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/utils/StringUtils.java +++ b/cloudinary-core/src/main/java/com/cloudinary/utils/StringUtils.java @@ -277,7 +277,7 @@ public static String mergeToSingleUnderscore(String s) { */ public static boolean isVariable(String s) { if (s == null || - s.length() < 3 || + s.length() < 2 || !s.startsWith("$") || !Character.isLetter(s.charAt(1))) { return false; diff --git a/cloudinary-core/src/test/java/com/cloudinary/UtilTest.java b/cloudinary-core/src/test/java/com/cloudinary/UtilTest.java index 8f8f5e15..6794e277 100644 --- a/cloudinary-core/src/test/java/com/cloudinary/UtilTest.java +++ b/cloudinary-core/src/test/java/com/cloudinary/UtilTest.java @@ -76,8 +76,8 @@ public void testIsVariable(){ assertTrue(StringUtils.isVariable("$ab")); assertTrue(StringUtils.isVariable("$asdasda")); assertTrue(StringUtils.isVariable("$a34asd12e")); + assertTrue(StringUtils.isVariable("$a")); - assertFalse(StringUtils.isVariable("$a")); assertFalse(StringUtils.isVariable("sda")); assertFalse(StringUtils.isVariable(" ")); assertFalse(StringUtils.isVariable("... . /")); @@ -159,4 +159,4 @@ public void testRemoveStartingChars(){ assertEquals("bcde", StringUtils.removeStartingChars("aaaaaabcde", 'a')); assertEquals("bcdeaa", StringUtils.removeStartingChars("aaaaaabcdeaa", 'a')); } -} \ No newline at end of file +} From 95d2b33206caa7830c6974eebf377b4a7dabf17f Mon Sep 17 00:00:00 2001 From: Yomes <1785648+YomesInc@users.noreply.github.com> Date: Tue, 1 Mar 2022 11:16:55 +0200 Subject: [PATCH 046/150] Fix post-test cleanup for `eval` upload parameter --- .../com/cloudinary/test/AbstractUploaderTest.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java index f37d2fbd..6925927c 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java @@ -34,8 +34,7 @@ abstract public class AbstractUploaderTest extends MockableTest { private static final String UPLOADER_TEST_PUBLIC_ID = "uploader_test"; public static final String SRC_FULLY_QUALIFIED_IMAGE="image/upload/" + UPLOADER_TEST_PUBLIC_ID; public static final String SRC_FULLY_QUALIFIED_VIDEO="video/upload/dog"; - public static final String SRC_TEST_EVAL= "if (resource_info['width'] < 450) { upload_options['tags'] = 'a,b' };" + "upload_options['context'] = 'width=' + resource_info['width'];"; - private static final ArrayList TEST_EVAL_TAGS_RESULT = new ArrayList(Arrays.asList("a","b")); + public static final String SRC_TEST_EVAL= "if (resource_info['width'] < 450) { upload_options['quality_analysis'] = true };" + "upload_options['context'] = 'width=' + resource_info['width'];"; @BeforeClass @@ -275,8 +274,12 @@ public void testImageUploadTag() { @Test public void testEvalUploadParameter() throws IOException { - Map result = cloudinary.uploader().upload(SRC_TEST_IMAGE, asMap("eval",SRC_TEST_EVAL)); - assertEquals(result.get("tags"), TEST_EVAL_TAGS_RESULT); + Map result = cloudinary.uploader().upload(SRC_TEST_IMAGE, asMap( + "eval",SRC_TEST_EVAL, + "tags", Arrays.asList(SDK_TEST_TAG, UPLOADER_TAG) + )); + assertTrue(result.get("quality_analysis")!=null && + ((HashMap)result.get("quality_analysis")).containsKey("focus")); Map custom= (Map)((Map) result.get("context")).get("custom"); assertEquals(custom.get("width"),Integer.toString(SRC_TEST_IMAGE_W)); } From 9e91064610afd671c75771f829b7f95a59dda380 Mon Sep 17 00:00:00 2001 From: Yomes <1785648+YomesInc@users.noreply.github.com> Date: Sun, 6 Mar 2022 17:49:05 +0200 Subject: [PATCH 047/150] Support `filename_override` upload parameter --- cloudinary-core/src/main/java/com/cloudinary/Util.java | 2 ++ .../java/com/cloudinary/test/AbstractUploaderTest.java | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/cloudinary-core/src/main/java/com/cloudinary/Util.java b/cloudinary-core/src/main/java/com/cloudinary/Util.java index 03b5965e..2333e1cf 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Util.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Util.java @@ -35,6 +35,8 @@ public static final Map buildUploadParams(Map options) { params.put("allowed_formats", StringUtils.join(ObjectUtils.asArray(options.get("allowed_formats")), ",")); params.put("moderation", options.get("moderation")); params.put("access_mode", (String) options.get("access_mode")); + params.put("filename_override", (String) options.get("filename_override")); + Object responsive_breakpoints = options.get("responsive_breakpoints"); if (responsive_breakpoints != null) { params.put("responsive_breakpoints", JSONObject.wrap(responsive_breakpoints)); diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java index 6925927c..d0f96181 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java @@ -562,6 +562,14 @@ public void testFilenameOption() throws Exception { assertEquals("emanelif", result.get("original_filename")); } + + @Test + public void testFilenameOverrideOption() throws Exception { + Map result = cloudinary.uploader().upload(SRC_TEST_IMAGE, asMap("filename_override", "overridden", "tags", Arrays.asList(SDK_TEST_TAG, UPLOADER_TAG))); + assertEquals("overridden", result.get("original_filename")); + } + + @Test public void testResponsiveBreakpoints() throws Exception { ResponsiveBreakpoint breakpoint = new ResponsiveBreakpoint() From 8a3c757458671322360c4312c0a592aef04433ff Mon Sep 17 00:00:00 2001 From: Yomes <1785648+YomesInc@users.noreply.github.com> Date: Sun, 6 Mar 2022 17:49:28 +0200 Subject: [PATCH 048/150] Support download backup version api --- .../src/main/java/com/cloudinary/Api.java | 3 +- .../main/java/com/cloudinary/Cloudinary.java | 28 ++++++ .../com/cloudinary/test/CloudinaryTest.java | 16 ++++ .../com/cloudinary/test/AbstractApiTest.java | 86 +++++++++++++++++++ 4 files changed, 132 insertions(+), 1 deletion(-) diff --git a/cloudinary-core/src/main/java/com/cloudinary/Api.java b/cloudinary-core/src/main/java/com/cloudinary/Api.java index d475f2b3..8b1caeee 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Api.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Api.java @@ -141,7 +141,7 @@ public ApiResponse resource(String public_id, Map options) throws Exception { ApiResponse response = callApi(HttpMethod.GET, Arrays.asList("resources", resourceType, type, public_id), ObjectUtils.only(options, "exif", "colors", "faces", "coordinates", "image_metadata", "pages", "phash", "max_results", "quality_analysis", "cinemagraph_analysis", - "accessibility_analysis"), options); + "accessibility_analysis", "versions"), options); return response; } @@ -302,6 +302,7 @@ public ApiResponse restore(Iterable publicIds, Map options) throws Excep String type = ObjectUtils.asString(options.get("type"), "upload"); Map params = new HashMap(); params.put("public_ids", publicIds); + params.put("versions", options.get("versions")); ApiResponse response = callApi(HttpMethod.POST, Arrays.asList("resources", resourceType, type, "restore"), params, options); return response; diff --git a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java index 64e0c45b..7fd3b80c 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java @@ -338,6 +338,34 @@ public String downloadFolder(String folderPath, Map options) throws UnsupportedE return downloadArchive(adjustedOptions, (String) adjustedOptions.get("target_format")); } + /** + * Returns an URL of a specific version of a backed up asset that can be used to download that + * version of the asset (within an hour of the request). + * + * @param assetId The identifier of the uploaded asset. + * @param versionId The identifier of a backed up version of the asset. + * @param options Optional, holds hints for URL generation procedure, see documentation for + * full list + * @return The download URL of the asset + */ + public String downloadBackedupAsset(String assetId, String versionId, Map options) throws UnsupportedEncodingException { + if (StringUtils.isEmpty(assetId)) { + throw new IllegalArgumentException("AssetId parameter is required"); + } + + if (StringUtils.isEmpty(versionId)) { + throw new IllegalArgumentException("VersionId parameter is required"); + } + + Map params = new HashMap(); + params.put("asset_id", assetId); + params.put("version_id", versionId); + params.put("timestamp", Util.timestamp()); + + signRequest(params, options); + return buildUrl(cloudinaryApiUrl("download_backup", options), params); + } + private String buildUrl(String base, Map params) throws UnsupportedEncodingException { StringBuilder urlBuilder = new StringBuilder(); urlBuilder.append(base); diff --git a/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java b/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java index 109b44ed..a911f92d 100644 --- a/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java +++ b/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java @@ -19,6 +19,7 @@ import java.lang.reflect.Modifier; import java.lang.reflect.Type; import java.net.URI; +import java.net.URISyntaxException; import java.net.URLDecoder; import java.net.URLEncoder; import java.util.*; @@ -1405,6 +1406,21 @@ public void testApiSignRequestSHA256() { assertEquals("45ddaa4fa01f0c2826f32f669d2e4514faf275fe6df053f1a150e7beae58a3bd", signature); } + @Test + public void testDownloadBackedupAsset() throws UnsupportedEncodingException, URISyntaxException { + String url = cloudinary.downloadBackedupAsset("62c2a18d622be7e190d21df8e05b1416", + "26fe6d95df856f6ae12f5678be94516a", ObjectUtils.emptyMap()); + + URI uri = new URI(url); + assertTrue(uri.getPath().endsWith("download_backup")); + + Map params = getUrlParameters(uri); + assertEquals("62c2a18d622be7e190d21df8e05b1416", params.get("asset_id")); + assertEquals("26fe6d95df856f6ae12f5678be94516a", params.get("version_id")); + assertNotNull(params.get("signature")); + assertNotNull(params.get("timestamp")); + } + private void assertFieldsEqual(Object a, Object b) throws IllegalAccessException { assertEquals("Two objects must be the same class", a.getClass(), b.getClass()); Field[] fields = a.getClass().getFields(); diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java index 0bc51d31..b9008aa6 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java @@ -829,6 +829,92 @@ public void testRestore() throws Exception { assertEquals(resource.get("bytes"), 3381); } + @Test + public void testRestoreDifferentVersionsOfDeletedAsset() throws Exception { + final String TEST_RESOURCE_PUBLIC_ID = "api_test_restore_different_versions_single_asset" + SUFFIX; + final Uploader uploader = cloudinary.uploader(); + + Map firstUpload = uploader.upload(SRC_TEST_IMAGE, + ObjectUtils.asMap( + "public_id", TEST_RESOURCE_PUBLIC_ID, + "backup", true, + "tags", UPLOAD_TAGS + )); + assertEquals(firstUpload.get("public_id"), TEST_RESOURCE_PUBLIC_ID); + ApiResponse firstDelete = api.deleteResources(Collections.singletonList(TEST_RESOURCE_PUBLIC_ID), ObjectUtils.emptyMap()); + assertTrue(firstDelete.containsKey("deleted")); + + Map secondUpload = uploader.upload(SRC_TEST_IMAGE, + ObjectUtils.asMap( + "public_id", TEST_RESOURCE_PUBLIC_ID, + "backup", true, + "transformation", new Transformation().angle("0"), + "tags", UPLOAD_TAGS + )); + assertEquals(secondUpload.get("public_id"), TEST_RESOURCE_PUBLIC_ID); + ApiResponse secondDelete = api.deleteResources(Collections.singletonList(TEST_RESOURCE_PUBLIC_ID), ObjectUtils.emptyMap()); + assertTrue(secondDelete.containsKey("deleted")); + + assertNotEquals(firstUpload.get("bytes"), secondUpload.get("bytes")); + + ApiResponse getVersionsResp = api.resource(TEST_RESOURCE_PUBLIC_ID, ObjectUtils.asMap("versions", true)); + List versions = (List) getVersionsResp.get("versions"); + Object firstAssetVersion = versions.get(0).get("version_id"); + Object secondAssetVersion = versions.get(1).get("version_id"); + + ApiResponse firstVerRestore = api.restore(Collections.singletonList(TEST_RESOURCE_PUBLIC_ID), + ObjectUtils.asMap("versions", Collections.singletonList(firstAssetVersion))); + assertEquals(((Map) firstVerRestore.get(TEST_RESOURCE_PUBLIC_ID)).get("bytes"), firstUpload.get("bytes")); + + ApiResponse secondVerRestore = api.restore(Collections.singletonList(TEST_RESOURCE_PUBLIC_ID), + ObjectUtils.asMap("versions", Collections.singletonList(secondAssetVersion))); + assertEquals(((Map) secondVerRestore.get(TEST_RESOURCE_PUBLIC_ID)).get("bytes"), secondUpload.get("bytes")); + + ApiResponse finalDeleteResp = api.deleteResources(Collections.singletonList(TEST_RESOURCE_PUBLIC_ID), ObjectUtils.emptyMap()); + assertTrue(finalDeleteResp.containsKey("deleted")); + } + + @Test + public void testShouldRestoreTwoDifferentDeletedAssets() throws Exception { + final String PUBLIC_ID_BACKUP_1 = "api_test_restore_versions_different_assets_1_" + SUFFIX; + final String PUBLIC_ID_BACKUP_2 = "api_test_restore_versions_different_assets_2_" + SUFFIX; + + final Uploader uploader = cloudinary.uploader(); + + Map firstUpload = uploader.upload(SRC_TEST_IMAGE, + ObjectUtils.asMap( + "public_id", PUBLIC_ID_BACKUP_1, + "backup", true, + "tags", UPLOAD_TAGS + )); + Map secondUpload = uploader.upload(SRC_TEST_IMAGE, + ObjectUtils.asMap( + "public_id", PUBLIC_ID_BACKUP_2, + "backup", true, + "transformation", new Transformation().angle("0"), + "tags", UPLOAD_TAGS + )); + + ApiResponse deleteAll = api.deleteResources(Arrays.asList(PUBLIC_ID_BACKUP_1, PUBLIC_ID_BACKUP_2), ObjectUtils.emptyMap()); + assertEquals("deleted", ((Map) deleteAll.get("deleted")).get(PUBLIC_ID_BACKUP_1)); + assertEquals("deleted", ((Map) deleteAll.get("deleted")).get(PUBLIC_ID_BACKUP_2)); + + ApiResponse getFirstAssetVersion = api.resource(PUBLIC_ID_BACKUP_1, ObjectUtils.asMap("versions", true)); + ApiResponse getSecondAssetVersion = api.resource(PUBLIC_ID_BACKUP_2, ObjectUtils.asMap("versions", true)); + + Object firstAssetVersion = ((List) getFirstAssetVersion.get("versions")).get(0).get("version_id"); + Object secondAssetVersion = ((List) getSecondAssetVersion.get("versions")).get(0).get("version_id"); + + ApiResponse restore = api.restore(Arrays.asList(PUBLIC_ID_BACKUP_1, PUBLIC_ID_BACKUP_2), + ObjectUtils.asMap("versions", Arrays.asList(firstAssetVersion, secondAssetVersion))); + assertEquals(((Map) restore.get(PUBLIC_ID_BACKUP_1)).get("bytes"), firstUpload.get("bytes")); + assertEquals(((Map) restore.get(PUBLIC_ID_BACKUP_2)).get("bytes"), secondUpload.get("bytes")); + + ApiResponse finalDelete = api.deleteResources(Arrays.asList(PUBLIC_ID_BACKUP_1, PUBLIC_ID_BACKUP_2), ObjectUtils.emptyMap()); + assertEquals("deleted", ((Map) finalDelete.get("deleted")).get(PUBLIC_ID_BACKUP_1)); + assertEquals("deleted", ((Map) finalDelete.get("deleted")).get(PUBLIC_ID_BACKUP_2)); + } + @Test public void testEncodeUrlInApiCall() throws Exception { String apiTestEncodeUrlInApiCall = "sub^folder test"; From c721dff98b720e8c291072496546fcfce8343d4b Mon Sep 17 00:00:00 2001 From: Yomes <1785648+YomesInc@users.noreply.github.com> Date: Thu, 10 Mar 2022 12:10:51 +0300 Subject: [PATCH 049/150] Implement missing tests Users API --- .../com/cloudinary/provisioning/Account.java | 4 +- .../test/AbstractAccountApiTest.java | 68 ++++++++++++++++++- 2 files changed, 69 insertions(+), 3 deletions(-) diff --git a/cloudinary-core/src/main/java/com/cloudinary/provisioning/Account.java b/cloudinary-core/src/main/java/com/cloudinary/provisioning/Account.java index 8c0f1eca..d81ee527 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/provisioning/Account.java +++ b/cloudinary-core/src/main/java/com/cloudinary/provisioning/Account.java @@ -283,7 +283,7 @@ public ApiResponse user(String userId, Map options) throws Excep /** * Get a list of the users according to filters. * - * @param pending Optional. Whether to fetch pending users. Default all. + * @param pending Optional. Limit results to pending users (true), users that are not pending (false), or all users (null) * @param userIds Optionals. List of user IDs. Up to 100 * @param prefix Optional. Search by prefix of the user's name or email. Case-insensitive * @param subAccountId Optional. Return only users who have access to the given sub-account @@ -297,7 +297,7 @@ public ApiResponse users(Boolean pending, List userIds, String prefix, S /** * Get a list of the users according to filters. * - * @param pending Optional. Whether to fetch pending users. Default all. + * @param pending Optional. Limit results to pending users (true), users that are not pending (false), or all users (null) * @param userIds Optionals. List of user IDs. Up to 100 * @param prefix Optional. Search by prefix of the user's name or email. Case-insensitive * @param subAccountId Optional. Return only users who have access to the given sub-account diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractAccountApiTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractAccountApiTest.java index a5d00fcb..8b35075e 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractAccountApiTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractAccountApiTest.java @@ -5,6 +5,7 @@ import com.cloudinary.api.ApiResponse; import com.cloudinary.provisioning.Account; import org.junit.*; +import org.junit.rules.ExpectedException; import org.junit.rules.TestName; import java.util.*; @@ -29,6 +30,8 @@ public static void setUpClass() { @Rule public TestName currentTest = new TestName(); + @Rule + public ExpectedException expectedException = ExpectedException.none(); @Before public void setUp() throws Exception { @@ -180,6 +183,63 @@ public void testGetUsers() throws Exception { deleteUser(user2Id); } + @Test + public void testGetPendingUsers() throws Exception { + String id = createUser(Account.Role.BILLING).get("id").toString(); + + ApiResponse pending = account.users(true, Collections.singletonList(id), null, null, null); + assertEquals(1, ((ArrayList) pending.get("users")).size()); + + ApiResponse notPending = account.users(false, Collections.singletonList(id), null, null, null); + assertEquals(0, ((ArrayList) notPending.get("users")).size()); + + ApiResponse all = account.users(null, Collections.singletonList(id), null, null, null); + assertEquals(1, ((ArrayList) all.get("users")).size()); + } + + @Test + public void testGetUsersByPrefix() throws Exception { + final long timeMillis = System.currentTimeMillis(); + final String userName = String.format("SDK TEST Get Users By Prefix %d", timeMillis); + final String userEmail = String.format("sdk-test-get-users-by-prefix+%d@cloudinary.com", timeMillis); + + createUser(userName, + userEmail, + Account.Role.BILLING, + Collections.emptyList()); + + ApiResponse userByPrefix = account.users(true, null, userName.substring(0, userName.length() - 1), null, null); + assertEquals(1, ((ArrayList) userByPrefix.get("users")).size()); + + ApiResponse userByNonExistingPrefix = account.users(true, null, userName + "zzz", null, null); + assertEquals(0, ((ArrayList) userByNonExistingPrefix.get("users")).size()); + } + + @Test + public void testGetUsersBySubAccountIds() throws Exception { + ApiResponse subAccount = createSubAccount(); + final String subAccountId = subAccount.get("id").toString(); + + final long timeMillis = System.currentTimeMillis(); + final String userName = String.format("SDK TEST Get Users By Sub Account Ids %d", timeMillis); + final String userEmail = String.format("sdk-test-get-users-by-sub-account-ids+%d@cloudinary.com", timeMillis); + + createUser(userName, + userEmail, + Account.Role.BILLING, + Collections.singletonList(subAccountId)); + + ApiResponse usersBySubAccount = account.users(true, null, userName, subAccountId, null); + assertEquals(1, ((ArrayList) usersBySubAccount.get("users")).size()); + } + + @Test + public void testGetUsersThrowsWhenSubAccountIdDoesntExist() throws Exception { + final String subAccountId = randomLetters(); + expectedException.expectMessage("Cannot find sub account with id " + subAccountId); + account.users(true, null, null, subAccountId, null); + } + @Test public void testCreateUser() throws Exception { ApiResponse createResult = createSubAccount(); @@ -294,6 +354,7 @@ private ApiResponse createGroup() throws Exception { ApiResponse userGroup = account.createUserGroup(name); createdGroupIds.add(userGroup.get("id").toString()); return userGroup; + } private ApiResponse createUser(Account.Role role) throws Exception { @@ -310,7 +371,11 @@ private ApiResponse createUser(List subAccountsIds) throws Exception { private ApiResponse createUser(List subAccountsIds, Account.Role role) throws Exception { String email = String.format("%s@%s.com", randomLetters(), randomLetters()); - ApiResponse user = account.createUser("TestUserJava"+new Date().toString(), email, role, subAccountsIds, null); + return createUser("TestName", email, role, subAccountsIds); + } + + private ApiResponse createUser(final String name, String email, Account.Role role, List subAccountsIds) throws Exception { + ApiResponse user = account.createUser(name, email, role, subAccountsIds, null); createdUserIds.add(user.get("id").toString()); return user; } @@ -336,6 +401,7 @@ private static String randomLetters() { for (int i = 0; i < 10; i++) { sb.append((char) ('a' + rand.nextInt('z' - 'a' + 1))); } + return sb.toString(); } } From c233ce68369ef5bdd9ee33454a47f97a3ee0d2a1 Mon Sep 17 00:00:00 2001 From: Yomes <1785648+YomesInc@users.noreply.github.com> Date: Mon, 14 Mar 2022 12:58:00 +0300 Subject: [PATCH 050/150] Allow to disable b-frames --- .../java/com/cloudinary/Transformation.java | 3 +++ .../com/cloudinary/test/CloudinaryTest.java | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/cloudinary-core/src/main/java/com/cloudinary/Transformation.java b/cloudinary-core/src/main/java/com/cloudinary/Transformation.java index f1efd89c..8b3d8c40 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Transformation.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Transformation.java @@ -923,6 +923,9 @@ private static String processVideoCodecParam(Object param) { outParam.append(":").append(paramMap.get("profile")); if (paramMap.containsKey("level")) { outParam.append(":").append(paramMap.get("level")); + if (paramMap.containsKey("b_frames") && paramMap.get("b_frames") == "false") { + outParam.append(":").append("bframes_no"); + } } } } diff --git a/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java b/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java index a911f92d..f4f94c43 100644 --- a/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java +++ b/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java @@ -879,6 +879,24 @@ public void testVideoCodec() { assertEquals(VIDEO_UPLOAD_PATH + "vc_h264:basic:3.1/video_id", actual); } + @Test + public void testVideoCodecBFrameTrue() { + String actual = cloudinary.url().resourceType("video") + .transformation( + new Transformation().videoCodec(asMap("codec", "h264", "profile", "basic", "level", "3.1", "b_frames", "true")) + ).generate("video_id"); + assertEquals(VIDEO_UPLOAD_PATH + "vc_h264:basic:3.1/video_id", actual); + } + + @Test + public void testVideoCodecBFrameFalse() { + String actual = cloudinary.url().resourceType("video") + .transformation( + new Transformation().videoCodec(asMap("codec", "h264", "profile", "basic", "level", "3.1", "b_frames", "false")) + ).generate("video_id"); + assertEquals(VIDEO_UPLOAD_PATH + "vc_h264:basic:3.1:bframes_no/video_id", actual); + } + @Test public void testAudioCodec() { // should support a string value From 709f4a9e0d230bfd5d523d2c2e1bc0afc36d1019 Mon Sep 17 00:00:00 2001 From: Yomes <1785648+YomesInc@users.noreply.github.com> Date: Mon, 14 Mar 2022 12:58:52 +0300 Subject: [PATCH 051/150] Add lowercase support for headers in API responses --- .../src/test/java/com/cloudinary/TransformationTest.java | 2 +- .../src/main/java/com/cloudinary/http42/api/Response.java | 2 +- .../src/main/java/com/cloudinary/http43/api/Response.java | 2 +- .../src/main/java/com/cloudinary/http44/api/Response.java | 2 +- .../src/main/java/com/cloudinary/http45/api/Response.java | 2 +- .../main/java/com/cloudinary/test/AbstractApiTest.java | 8 ++++++++ 6 files changed, 13 insertions(+), 5 deletions(-) diff --git a/cloudinary-core/src/test/java/com/cloudinary/TransformationTest.java b/cloudinary-core/src/test/java/com/cloudinary/TransformationTest.java index a3de2700..2ff10486 100644 --- a/cloudinary-core/src/test/java/com/cloudinary/TransformationTest.java +++ b/cloudinary-core/src/test/java/com/cloudinary/TransformationTest.java @@ -300,4 +300,4 @@ public void testContextMetadataToUserVariables() { assertEquals("$xpos_ctx:!x_pos!_to_f,$ypos_ctx:!y_pos!_to_f,c_crop,x_$xpos_mul_w,y_$ypos_mul_h", t.generate()); } -} \ No newline at end of file +} diff --git a/cloudinary-http42/src/main/java/com/cloudinary/http42/api/Response.java b/cloudinary-http42/src/main/java/com/cloudinary/http42/api/Response.java index dfe44ed6..87de8299 100644 --- a/cloudinary-http42/src/main/java/com/cloudinary/http42/api/Response.java +++ b/cloudinary-http42/src/main/java/com/cloudinary/http42/api/Response.java @@ -32,7 +32,7 @@ public HttpResponse getRawHttpResponse() { } private static final Pattern RATE_LIMIT_REGEX = Pattern - .compile("X-Feature(\\w*)RateLimit(-Limit|-Reset|-Remaining)"); + .compile("X-FEATURE(\\w*)RATELIMIT(-LIMIT|-RESET|-REMAINING)", Pattern.CASE_INSENSITIVE); private static final String RFC1123_PATTERN = "EEE, dd MMM yyyyy HH:mm:ss z"; private static final DateFormat RFC1123 = new SimpleDateFormat(RFC1123_PATTERN, Locale.ENGLISH); diff --git a/cloudinary-http43/src/main/java/com/cloudinary/http43/api/Response.java b/cloudinary-http43/src/main/java/com/cloudinary/http43/api/Response.java index fd4bfa58..51cd9219 100644 --- a/cloudinary-http43/src/main/java/com/cloudinary/http43/api/Response.java +++ b/cloudinary-http43/src/main/java/com/cloudinary/http43/api/Response.java @@ -31,7 +31,7 @@ public HttpResponse getRawHttpResponse() { } private static final Pattern RATE_LIMIT_REGEX = Pattern - .compile("X-Feature(\\w*)RateLimit(-Limit|-Reset|-Remaining)"); + .compile("X-FEATURE(\\w*)RATELIMIT(-LIMIT|-RESET|-REMAINING)", Pattern.CASE_INSENSITIVE); private static final String RFC1123_PATTERN = "EEE, dd MMM yyyyy HH:mm:ss z"; private static final DateFormat RFC1123 = new SimpleDateFormat(RFC1123_PATTERN, Locale.ENGLISH); diff --git a/cloudinary-http44/src/main/java/com/cloudinary/http44/api/Response.java b/cloudinary-http44/src/main/java/com/cloudinary/http44/api/Response.java index 0beb97c5..0036d453 100644 --- a/cloudinary-http44/src/main/java/com/cloudinary/http44/api/Response.java +++ b/cloudinary-http44/src/main/java/com/cloudinary/http44/api/Response.java @@ -31,7 +31,7 @@ public HttpResponse getRawHttpResponse() { } private static final Pattern RATE_LIMIT_REGEX = Pattern - .compile("X-Feature(\\w*)RateLimit(-Limit|-Reset|-Remaining)"); + .compile("X-FEATURE(\\w*)RATELIMIT(-LIMIT|-RESET|-REMAINING)", Pattern.CASE_INSENSITIVE); private static final String RFC1123_PATTERN = "EEE, dd MMM yyyyy HH:mm:ss z"; private static final DateFormat RFC1123 = new SimpleDateFormat(RFC1123_PATTERN, Locale.ENGLISH); diff --git a/cloudinary-http45/src/main/java/com/cloudinary/http45/api/Response.java b/cloudinary-http45/src/main/java/com/cloudinary/http45/api/Response.java index 6cb29455..08121401 100644 --- a/cloudinary-http45/src/main/java/com/cloudinary/http45/api/Response.java +++ b/cloudinary-http45/src/main/java/com/cloudinary/http45/api/Response.java @@ -31,7 +31,7 @@ public HttpResponse getRawHttpResponse() { } private static final Pattern RATE_LIMIT_REGEX = Pattern - .compile("X-Feature(\\w*)RateLimit(-Limit|-Reset|-Remaining)"); + .compile("X-FEATURE(\\w*)RATELIMIT(-LIMIT|-RESET|-REMAINING)", Pattern.CASE_INSENSITIVE); private static final String RFC1123_PATTERN = "EEE, dd MMM yyyyy HH:mm:ss z"; private static final DateFormat RFC1123 = new SimpleDateFormat(RFC1123_PATTERN, Locale.ENGLISH); diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java index b9008aa6..c124b11e 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java @@ -557,6 +557,14 @@ public void testRateLimitWithNonEnglishLocale() throws Exception { Assert.assertNotNull(result.apiRateLimit().getReset()); } + @Test + public void testRateLimits() throws Exception { + ApiResponse result = cloudinary.api().usage(new HashMap()); + Assert.assertNotEquals(0, result.apiRateLimit().getLimit()); + Assert.assertNotNull(result.apiRateLimit().getReset()); + Assert.assertNotEquals(0, result.apiRateLimit().getRemaining()); + } + @Test public void test19Ping() throws Exception { // should support ping API call From ac5ab2d0a8d427b4d6d62d2ad99bcadd6df0016e Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Mon, 14 Mar 2022 14:24:16 +0200 Subject: [PATCH 052/150] Add tags as an array (#252) * Add addTag and removeTag to receive Strings array * Add add tag function to recieve multiple tags * Add test * Add replace tag as array * Fix addTag, removeTag, replaceTag * Fix comment --- .../main/java/com/cloudinary/Uploader.java | 101 +++++++++++++++++- .../cloudinary/test/AbstractUploaderTest.java | 18 +++- 2 files changed, 113 insertions(+), 6 deletions(-) diff --git a/cloudinary-core/src/main/java/com/cloudinary/Uploader.java b/cloudinary-core/src/main/java/com/cloudinary/Uploader.java index 65d74a0f..0531161e 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Uploader.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Uploader.java @@ -323,9 +323,35 @@ public Map explode(String public_id, Map options) throws IOException { return callApi("explode", params, options, null); } - // options may include 'exclusive' (boolean) which causes clearing this tag - // from all other resources + /** + * Add a tag to one or more assets in your cloud. + * Tags are used to categorize and organize your images, and can also be used to apply group actions to images, + * for example to delete images, create sprites, ZIP files, JSON lists, or animated GIFs. + * Each image can be assigned one or more tags, which is a short name that you can dynamically use (no need to predefine tags). + * @param tag - The tag to assign. + * @param publicIds - An array of Public IDs of images uploaded to Cloudinary. + * @param options - An object holding the available parameters for the request. + * options may include 'exclusive' (boolean) which causes clearing this tag from all other resources + * @return A map with the public ids returned from the server + * @throws IOException + */ public Map addTag(String tag, String[] publicIds, Map options) throws IOException { + return addTag(new String[]{tag}, publicIds, options); + } + + /** + * Add a tag to one or more assets in your cloud. + * Tags are used to categorize and organize your images, and can also be used to apply group actions to images, + * for example to delete images, create sprites, ZIP files, JSON lists, or animated GIFs. + * Each image can be assigned one or more tags, which is a short name that you can dynamically use (no need to predefine tags). + * @param tag - An array of tags to assign. + * @param publicIds - An array of Public IDs of images uploaded to Cloudinary. + * @param options - An object holding the available parameters for the request. + * options may include 'exclusive' (boolean) which causes clearing this tag from all other resources + * @return A map with the public ids returned from the server. + * @throws IOException + */ + public Map addTag(String[] tag, String[] publicIds, Map options) throws IOException { if (options == null) options = ObjectUtils.emptyMap(); boolean exclusive = ObjectUtils.asBoolean(options.get("exclusive"), false); @@ -333,30 +359,97 @@ public Map addTag(String tag, String[] publicIds, Map options) throws IOExceptio return callTagsApi(tag, command, publicIds, options); } + /** + * Remove a tag to one or more assets in your cloud. + * Tags are used to categorize and organize your images, and can also be used to apply group actions to images, + * for example to delete images, create sprites, ZIP files, JSON lists, or animated GIFs. + * Each image can be assigned one or more tags, which is a short name that you can dynamically use (no need to predefine tags). + * @param tag - The tag to remove. + * @param publicIds - An array of Public IDs of images uploaded to Cloudinary. + * @param options - An object holding the available parameters for the request. + * options may include 'exclusive' (boolean) which causes clearing this tag from all other resources + * @return - A map with the public ids returned from the server. + * @throws IOException + */ public Map removeTag(String tag, String[] publicIds, Map options) throws IOException { + return removeTag(new String[]{tag}, publicIds, options); + } + + /** + * Remove tags to one or more assets in your cloud. + * Tags are used to categorize and organize your images, and can also be used to apply group actions to images, + * for example to delete images, create sprites, ZIP files, JSON lists, or animated GIFs. + * Each image can be assigned one or more tags, which is a short name that you can dynamically use (no need to predefine tags). + * @param tag - The array of tags to remove. + * @param publicIds - An array of Public IDs of images uploaded to Cloudinary. + * @param options - An object holding the available parameters for the request. + * options may include 'exclusive' (boolean) which causes clearing this tag from all other resources + * @return - * @return - A map with the public ids returned from the server. + * @throws IOException + */ + public Map removeTag(String[] tag, String[] publicIds, Map options) throws IOException { if (options == null) options = ObjectUtils.emptyMap(); return callTagsApi(tag, Command.remove, publicIds, options); } + /** + * Remove an array of tags to one or more assets in your cloud. + * Tags are used to categorize and organize your images, and can also be used to apply group actions to images, + * for example to delete images, create sprites, ZIP files, JSON lists, or animated GIFs. + * Each image can be assigned one or more tags, which is a short name that you can dynamically use (no need to predefine tags). + * @param publicIds - An array of Public IDs of images uploaded to Cloudinary. + * @param options - An object holding the available parameters for the request. + * options may include 'exclusive' (boolean) which causes clearing this tag from all other resources + * @return - * @return - A map with the public ids returned from the server. + * @throws IOException + */ public Map removeAllTags(String[] publicIds, Map options) throws IOException { if (options == null) options = ObjectUtils.emptyMap(); return callTagsApi(null, Command.removeAll, publicIds, options); } + /** + * Replaces a tag to one or more assets in your cloud. + * Tags are used to categorize and organize your images, and can also be used to apply group actions to images, + * for example to delete images, create sprites, ZIP files, JSON lists, or animated GIFs. + * Each image can be assigned one or more tags, which is a short name that you can dynamically use (no need to predefine tags). + * @param tag - The tag to replace. + * @param publicIds - An array of Public IDs of images uploaded to Cloudinary. + * @param options - An object holding the available options for the request. + * options may include 'exclusive' (boolean) which causes clearing this tag from all other resources + * @return - A map with the public ids returned from the server. + * @throws IOException + */ public Map replaceTag(String tag, String[] publicIds, Map options) throws IOException { + return replaceTag(new String[]{tag}, publicIds, options); + } + + /** + * Replaces tags to one or more assets in your cloud. + * Tags are used to categorize and organize your images, and can also be used to apply group actions to images, + * for example to delete images, create sprites, ZIP files, JSON lists, or animated GIFs. + * Each image can be assigned one or more tags, which is a short name that you can dynamically use (no need to predefine tags). + * @param tag - An array of tag to replace. + * @param publicIds - An array of Public IDs of images uploaded to Cloudinary. + * @param options - An object holding the available options for the request. + * options may include 'exclusive' (boolean) which causes clearing this tag from all other resources + * @return - A map with the public ids returned from the server. + * @throws IOException + */ + public Map replaceTag(String[] tag, String[] publicIds, Map options) throws IOException { if (options == null) options = ObjectUtils.emptyMap(); return callTagsApi(tag, Command.replace, publicIds, options); } - public Map callTagsApi(String tag, String command, String[] publicIds, Map options) throws IOException { + public Map callTagsApi(String[] tag, String command, String[] publicIds, Map options) throws IOException { if (options == null) options = ObjectUtils.emptyMap(); Map params = new HashMap(); if (tag != null) { - params.put("tag", tag); + params.put("tag", StringUtils.join(tag, ",")); } params.put("command", command); params.put("type", (String) options.get("type")); diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java index d0f96181..bfce72dd 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java @@ -342,21 +342,35 @@ public void testTags() throws Exception { Map result2 = cloudinary.uploader().upload(SRC_TEST_IMAGE, ObjectUtils.emptyMap()); String public_id2 = (String) result2.get("public_id"); addToDeleteList("upload", public_id2); + + //Test add tags cloudinary.uploader().addTag("tag1", new String[]{public_id, public_id2}, ObjectUtils.emptyMap()); cloudinary.uploader().addTag("tag2", new String[]{public_id}, ObjectUtils.emptyMap()); + cloudinary.uploader().addTag(new String[]{"tag4","tag5"}, new String[]{public_id}, ObjectUtils.emptyMap()); List tags = (List) cloudinary.api().resource(public_id, ObjectUtils.emptyMap()).get("tags"); - assertEquals(tags, asArray(new String[]{"tag1", "tag2"})); + assertEquals(tags, asArray(new String[]{"tag1", "tag2", "tag4", "tag5"})); tags = (List) cloudinary.api().resource(public_id2, ObjectUtils.emptyMap()).get("tags"); assertEquals(tags, asArray(new String[]{"tag1"})); + + //Test remove tags cloudinary.uploader().removeTag("tag1", new String[]{public_id}, ObjectUtils.emptyMap()); tags = (List) cloudinary.api().resource(public_id, ObjectUtils.emptyMap()).get("tags"); + assertEquals(tags, asArray(new String[]{"tag2", "tag4", "tag5"})); + cloudinary.uploader().removeTag(new String[]{"tag4", "tag5"}, new String[]{public_id}, ObjectUtils.emptyMap()); + tags = (List) cloudinary.api().resource(public_id, ObjectUtils.emptyMap()).get("tags"); assertEquals(tags, asArray(new String[]{"tag2"})); + + //Test replace tags cloudinary.uploader().replaceTag("tag3", new String[]{public_id}, ObjectUtils.emptyMap()); tags = (List) cloudinary.api().resource(public_id, ObjectUtils.emptyMap()).get("tags"); assertEquals(tags, asArray(new String[]{"tag3"})); + cloudinary.uploader().replaceTag(new String[]{"tag6", "tag7"}, new String[]{public_id}, ObjectUtils.emptyMap()); + tags = (List) cloudinary.api().resource(public_id, ObjectUtils.emptyMap()).get("tags"); + assertEquals(tags, asArray(new String[]{"tag6", "tag7"})); + + //Test remove all tags result = cloudinary.uploader().removeAllTags(new String[]{public_id, public_id2, "noSuchId"}, ObjectUtils.emptyMap()); List publicIds = (List) result.get("public_ids"); - assertThat(publicIds, containsInAnyOrder(public_id, public_id2)); // = and not containing "noSuchId" result = cloudinary.api().resource(public_id, ObjectUtils.emptyMap()); assertThat((Map) result, not(hasKey("tags"))); From d0bc4bdeb9502840790d21d6edead4856fdf6da2 Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Mon, 14 Mar 2022 15:33:51 +0200 Subject: [PATCH 053/150] Add `enabled` parameter to `updateUser`, `replaceUser` and `createUser` --- .../com/cloudinary/provisioning/Account.java | 47 +++++++++-- .../test/AbstractAccountApiTest.java | 79 +++++++++++++++++-- 2 files changed, 113 insertions(+), 13 deletions(-) diff --git a/cloudinary-core/src/main/java/com/cloudinary/provisioning/Account.java b/cloudinary-core/src/main/java/com/cloudinary/provisioning/Account.java index d81ee527..55860aa5 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/provisioning/Account.java +++ b/cloudinary-core/src/main/java/com/cloudinary/provisioning/Account.java @@ -5,7 +5,6 @@ import com.cloudinary.Util; import com.cloudinary.api.ApiResponse; import com.cloudinary.utils.ObjectUtils; - import java.util.*; /** @@ -327,7 +326,7 @@ public ApiResponse users(Boolean pending, List userIds, String prefix, S * @throws Exception If the request fails. */ public ApiResponse createUser(String name, String email, Role role, List subAccountsIds) throws Exception { - return createUser(name, email, role, subAccountsIds); + return createUser(name, email, role, subAccountsIds, null); } /** @@ -343,8 +342,25 @@ public ApiResponse createUser(String name, String email, Role role, List * @throws Exception If the request fails. */ public ApiResponse createUser(String name, String email, Role role, List subAccountsIds, Map options) throws Exception { + return createUser(name, email, role, null, subAccountsIds, options); + } + + /** + * Create a new user. + * + * @param name Required. Username. + * @param email Required. User's email. + * @param role Required. User's role. + * @param enabled Optional. User's status (enabled or disabled). + * @param subAccountsIds Optional. Sub-accounts for which the user should have access. + * If not provided or empty, user should have access to all accounts. + * @param options Generic advanced options map, see online documentation. + * @return The newly created user details. + * @throws Exception If the request fails. + */ + public ApiResponse createUser(String name, String email, Role role, Boolean enabled, List subAccountsIds, Map options) throws Exception { List uri = Arrays.asList(PROVISIONING, ACCOUNTS, accountId, USERS); - return performUserAction(Api.HttpMethod.POST, uri, email, name, role, subAccountsIds, options); + return performUserAction(Api.HttpMethod.POST, uri, email, name, role, enabled, subAccountsIds, options); } /** @@ -377,8 +393,26 @@ public ApiResponse updateUser(String userId, String name, String email, Role rol * @throws Exception If the request fails. */ public ApiResponse updateUser(String userId, String name, String email, Role role, List subAccountsIds, Map options) throws Exception { + return updateUser(userId, name ,email ,role ,null , subAccountsIds , options); + } + + /** + * Update an existing user. + * + * @param userId The id of the user to update. + * @param name Username. + * @param email User's email. + * @param role User's role. + * @param enabled User's status (enabled or disabled) + * @param subAccountsIds Sub-accounts for which the user should have access. + * If not provided or empty, user should have access to all accounts. + * @param options Generic advanced options map, see online documentation. + * @return The updated user details + * @throws Exception If the request fails. + */ + public ApiResponse updateUser(String userId, String name, String email, Role role, Boolean enabled, List subAccountsIds, Map options) throws Exception { List uri = Arrays.asList(PROVISIONING, ACCOUNTS, accountId, USERS, userId); - return performUserAction(Api.HttpMethod.PUT, uri, email, name, role, subAccountsIds, options); + return performUserAction(Api.HttpMethod.PUT, uri, email, name, role, enabled, subAccountsIds, options); } /** @@ -597,7 +631,7 @@ public ApiResponse userGroupUsers(String groupId, Map options) t * @return The response of the api call. * @throws Exception If the request fails. */ - private ApiResponse performUserAction(Api.HttpMethod method, List uri, String email, String name, Role role, List subAccountsIds, Map options) throws Exception { + private ApiResponse performUserAction(Api.HttpMethod method, List uri, String email, String name, Role role, Boolean enabled, List subAccountsIds, Map options) throws Exception { options = verifyOptions(options); options.put("content_type", "json"); @@ -605,6 +639,7 @@ private ApiResponse performUserAction(Api.HttpMethod method, List uri, S "email", email, "name", name, "role", role == null ? null : role.serializedValue, + "enabled", enabled, "sub_account_ids", subAccountsIds), options); } @@ -616,4 +651,4 @@ private Map verifyOptions(Map options) { return options; } -} \ No newline at end of file +} diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractAccountApiTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractAccountApiTest.java index 8b35075e..0fe3c95a 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractAccountApiTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractAccountApiTest.java @@ -4,6 +4,7 @@ import com.cloudinary.Cloudinary; import com.cloudinary.api.ApiResponse; import com.cloudinary.provisioning.Account; +import com.cloudinary.utils.ObjectUtils; import org.junit.*; import org.junit.rules.ExpectedException; import org.junit.rules.TestName; @@ -13,8 +14,7 @@ import static java.util.Collections.emptyMap; import static java.util.Collections.singletonMap; import static junit.framework.TestCase.assertTrue; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.*; public abstract class AbstractAccountApiTest extends MockableTest { private static Random rand = new Random(); @@ -247,6 +247,27 @@ public void testCreateUser() throws Exception { assertNotNull(result); } + @Test + public void testCreateUserWithOptions() throws Exception { + ApiResponse createResult = createSubAccount(); + ApiResponse result = createUser(Collections.singletonList(createResult.get("id").toString()), ObjectUtils.emptyMap()); + assertNotNull(result); + } + + @Test + public void testCreateUserEnabled() throws Exception { + ApiResponse createResult = createSubAccount(); + ApiResponse result = createUser(Collections.singletonList(createResult.get("id").toString()), true); + assertTrue((Boolean) result.get("enabled")); + } + + @Test + public void testCreateUserDisabled() throws Exception { + ApiResponse createResult = createSubAccount(); + ApiResponse result = createUser(Collections.singletonList(createResult.get("id").toString()), false); + assertFalse((Boolean) result.get("enabled")); + } + @Test public void testUpdateUser() throws Exception { ApiResponse user = createUser(Account.Role.ADMIN); @@ -259,6 +280,30 @@ public void testUpdateUser() throws Exception { deleteUser(userId); } + @Test + public void testUpdateUserEnabled() throws Exception { + ApiResponse user = createUser(Account.Role.ADMIN); + String userId = user.get("id").toString(); + String newName = randomLetters(); + ApiResponse result = account.updateUser(userId, newName, null, null, true, null, null); + + assertNotNull(result); + assertTrue((Boolean) result.get("enabled")); + deleteUser(userId); + } + + @Test + public void testUpdateUserDisabled() throws Exception { + ApiResponse user = createUser(Account.Role.ADMIN); + String userId = user.get("id").toString(); + String newName = randomLetters(); + ApiResponse result = account.updateUser(userId, newName, null, null, false, null, null); + + assertNotNull(result); + assertFalse((Boolean) result.get("enabled")); + deleteUser(userId); + } + @Test public void testDeleteUser() throws Exception { ApiResponse user = createUser(Collections.emptyList()); @@ -354,26 +399,47 @@ private ApiResponse createGroup() throws Exception { ApiResponse userGroup = account.createUserGroup(name); createdGroupIds.add(userGroup.get("id").toString()); return userGroup; + } + private ApiResponse createUser() throws Exception { + return createUser(Collections.emptyList()); } private ApiResponse createUser(Account.Role role) throws Exception { return createUser(Collections.emptyList(), role); } - private ApiResponse createUser() throws Exception { - return createUser(Collections.emptyList()); - } - private ApiResponse createUser(List subAccountsIds) throws Exception { return createUser(subAccountsIds, Account.Role.BILLING); } + private ApiResponse createUser(List subAccountsIds, Map options) throws Exception { + return createUser(subAccountsIds, Account.Role.BILLING, options); + } + + private ApiResponse createUser(List subAccountsIds, Boolean enabled) throws Exception { + return createUser(subAccountsIds, Account.Role.BILLING, enabled); + } + private ApiResponse createUser(List subAccountsIds, Account.Role role) throws Exception { String email = String.format("%s@%s.com", randomLetters(), randomLetters()); return createUser("TestName", email, role, subAccountsIds); } + private ApiResponse createUser(List subAccountsIds, Account.Role role, Map options) throws Exception { + String email = String.format("%s@%s.com", randomLetters(), randomLetters()); + ApiResponse user = account.createUser("TestUserJava"+new Date().toString(), email, role, null, subAccountsIds, options); + createdUserIds.add(user.get("id").toString()); + return user; + } + + private ApiResponse createUser(List subAccountsIds, Account.Role role, Boolean enabled) throws Exception { + String email = String.format("%s@%s.com", randomLetters(), randomLetters()); + ApiResponse user = account.createUser("TestUserJava"+new Date().toString(), email, role, enabled, subAccountsIds, null); + createdUserIds.add(user.get("id").toString()); + return user; + } + private ApiResponse createUser(final String name, String email, Account.Role role, List subAccountsIds) throws Exception { ApiResponse user = account.createUser(name, email, role, subAccountsIds, null); createdUserIds.add(user.get("id").toString()); @@ -401,7 +467,6 @@ private static String randomLetters() { for (int i = 0; i < 10; i++) { sb.append((char) ('a' + rand.nextInt('z' - 'a' + 1))); } - return sb.toString(); } } From f964084cafbc2a03045547a2b7ac8fcf2c2b504d Mon Sep 17 00:00:00 2001 From: Yomes <1785648+YomesInc@users.noreply.github.com> Date: Thu, 17 Mar 2022 10:04:42 +0300 Subject: [PATCH 054/150] Get resources by asset id --- .../src/main/java/com/cloudinary/Api.java | 8 ++++++++ .../java/com/cloudinary/test/AbstractApiTest.java | 15 +++++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/cloudinary-core/src/main/java/com/cloudinary/Api.java b/cloudinary-core/src/main/java/com/cloudinary/Api.java index 8b1caeee..990ecc2d 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Api.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Api.java @@ -115,6 +115,14 @@ public ApiResponse resourcesByContext(String key, String value, Map options) thr return callApi(HttpMethod.GET, Arrays.asList("resources", resourceType, "context"), params, options); } + public ApiResponse resourcesByAssetIDs(Iterable assetIds, Map options) throws Exception { + if (options == null) options = ObjectUtils.emptyMap(); + Map params = ObjectUtils.only(options, "public_ids", "tags", "context", "moderations"); + params.put("asset_ids", assetIds); + ApiResponse response = callApi(HttpMethod.GET, Arrays.asList("resources", "by_asset_ids"), params, options); + return response; + } + public ApiResponse resourcesByIds(Iterable publicIds, Map options) throws Exception { if (options == null) options = ObjectUtils.emptyMap(); String resourceType = ObjectUtils.asString(options.get("resource_type"), "image"); diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java index c124b11e..d950ac6f 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java @@ -49,6 +49,8 @@ abstract public class AbstractApiTest extends MockableTest { public static final Set createdFolders = new HashSet(); private static final String CUSTOM_USER_AGENT_PREFIX = "TEST_USER_AGENT"; private static final String CUSTOM_USER_AGENT_VERSION = "9.9.9"; + private static String assetId1; + private static String assetId2; protected Api api; @@ -66,10 +68,10 @@ public static void setUpClass() throws IOException { Map options = ObjectUtils.asMap("public_id", API_TEST, "tags", uploadAndDirectionTag, "context", "key=value", "eager", Collections.singletonList(EXPLICIT_TRANSFORMATION)); - cloudinary.uploader().upload(SRC_TEST_IMAGE, options); + assetId1 = cloudinary.uploader().upload(SRC_TEST_IMAGE, options).get("asset_id").toString(); options.put("public_id", API_TEST_1); - cloudinary.uploader().upload(SRC_TEST_IMAGE, options); + assetId2 = cloudinary.uploader().upload(SRC_TEST_IMAGE, options).get("asset_id").toString(); options.remove("public_id"); options.put("eager", Collections.singletonList(UPDATE_TRANSFORMATION)); @@ -269,6 +271,15 @@ public void testTransformationsWithCursor() throws Exception { assertThat(transformations, hasItem(allOf(hasEntry("name", "t_" + name)))); } + @Test + public void testResourcesByAssetIds() throws Exception { + Map result = api.resourcesByAssetIDs(Arrays.asList(assetId1, assetId2), ObjectUtils.asMap("tags", true, "context", true)); + List resources = (List) result.get("resources"); + assertEquals(2, resources.size()); + assertNotNull(findByAttr(resources, "public_id", API_TEST)); + assertNotNull(findByAttr(resources, "public_id", API_TEST_1)); + } + @Test public void testResourcesByPublicIds() throws Exception { // should allow listing resources by public ids From 66b7872c2f268283afb02eb2d1dc1abd0254a906 Mon Sep 17 00:00:00 2001 From: Yomes <1785648+YomesInc@users.noreply.github.com> Date: Thu, 17 Mar 2022 10:06:14 +0300 Subject: [PATCH 055/150] Disables provisioning tests if environment variable is not set --- cloudinary-http42/build.gradle | 5 ++++- cloudinary-http43/build.gradle | 5 ++++- cloudinary-http44/build.gradle | 5 ++++- cloudinary-http45/build.gradle | 5 ++++- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/cloudinary-http42/build.gradle b/cloudinary-http42/build.gradle index 6b1a0cba..cb8ec796 100644 --- a/cloudinary-http42/build.gradle +++ b/cloudinary-http42/build.gradle @@ -11,6 +11,9 @@ apply from: "../java_shared.gradle" task ciTest( type: Test ) { useJUnit { excludeCategories 'com.cloudinary.test.TimeoutTest' + if (System.getProperty("CLOUDINARY_ACCOUNT_URL") == "") { + exclude '**/AccountApiTest.class' + } } } @@ -118,4 +121,4 @@ if (hasProperty("ossrhPassword")) { } } } -} \ No newline at end of file +} diff --git a/cloudinary-http43/build.gradle b/cloudinary-http43/build.gradle index 53a0f238..6b22abc2 100644 --- a/cloudinary-http43/build.gradle +++ b/cloudinary-http43/build.gradle @@ -11,6 +11,9 @@ apply from: "../java_shared.gradle" task ciTest( type: Test ) { useJUnit { excludeCategories 'com.cloudinary.test.TimeoutTest' + if (System.getProperty("CLOUDINARY_ACCOUNT_URL") == "") { + exclude '**/AccountApiTest.class' + } } } @@ -117,4 +120,4 @@ if (hasProperty("ossrhPassword")) { } } } -} \ No newline at end of file +} diff --git a/cloudinary-http44/build.gradle b/cloudinary-http44/build.gradle index 1312d2b9..7d533e05 100644 --- a/cloudinary-http44/build.gradle +++ b/cloudinary-http44/build.gradle @@ -11,6 +11,9 @@ apply from: "../java_shared.gradle" task ciTest( type: Test ) { useJUnit { excludeCategories 'com.cloudinary.test.TimeoutTest' + if (System.getProperty("CLOUDINARY_ACCOUNT_URL") == "") { + exclude '**/AccountApiTest.class' + } } } @@ -117,4 +120,4 @@ if (hasProperty("ossrhPassword")) { } } } -} \ No newline at end of file +} diff --git a/cloudinary-http45/build.gradle b/cloudinary-http45/build.gradle index 13be8f83..2d88dc60 100644 --- a/cloudinary-http45/build.gradle +++ b/cloudinary-http45/build.gradle @@ -11,6 +11,9 @@ apply from: "../java_shared.gradle" task ciTest( type: Test ) { useJUnit { excludeCategories 'com.cloudinary.test.TimeoutTest' + if (System.getProperty("CLOUDINARY_ACCOUNT_URL") == "") { + exclude '**/AccountApiTest.class' + } } } @@ -117,4 +120,4 @@ if (hasProperty("ossrhPassword")) { } } } -} \ No newline at end of file +} From 9ab86add0c806c669b0fcb0e2071e3e1e2610ff7 Mon Sep 17 00:00:00 2001 From: adimiz1 Date: Mon, 21 Mar 2022 12:30:25 +0200 Subject: [PATCH 056/150] Version 1.31.0 --- CHANGELOG.md | 14 ++++++++++++++ README.md | 4 ++-- .../src/main/java/com/cloudinary/Cloudinary.java | 2 +- gradle.properties | 2 +- 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 98db5a9a..01a6586a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,18 @@ +1.31.0 / 2022-03-21 +==================== + +New functionality +----------------- + * Get resources by asset id + * Add `enabled` parameter to `updateUser`, `replaceUser` and `createUser` + * Add tags as an array + * Add lowercase support for headers in API responses + * Allow to disable b-frames + * Support download backup version api + * Support `filename_override` upload parameter + * Add support for single character variable + 1.30.0 / 2022-02-02 =================== diff --git a/README.md b/README.md index 08c54813..1b4cc58e 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ For the complete documentation, see the [Java SDK Guide](https://cloudinary.com/ ## Version Support | SDK Version | Java 6+ | |----------------|---------| -| 1.1.0 - 1.30.0 | V | +| 1.1.0 - 1.31.0 | V | ## Installation The cloudinary_java library is available in [Maven Central](https://mvnrepository.com/artifact/com.cloudinary/cloudinary-core). To use it, add the following dependency to your pom.xml : @@ -36,7 +36,7 @@ The cloudinary_java library is available in [Maven Central](https://mvnrepositor com.cloudinary cloudinary-http44 - 1.30.0 + 1.31.0 ``` diff --git a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java index 7fd3b80c..460beda5 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java @@ -38,7 +38,7 @@ public class Cloudinary { public final static String AKAMAI_SHARED_CDN = "res.cloudinary.com"; public final static String SHARED_CDN = AKAMAI_SHARED_CDN; - public final static String VERSION = "1.30.0"; + public final static String VERSION = "1.31.0"; static String USER_AGENT_PREFIX = "CloudinaryJava"; public final static String USER_AGENT_JAVA_VERSION = "(Java " + System.getProperty("java.version") + ")"; diff --git a/gradle.properties b/gradle.properties index 1c79d617..d601b863 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,7 +13,7 @@ developerEmail=info@cloudinary.com # These two properties must use these exact names to be compatible with 'gradle install' plugin. group=com.cloudinary -version=1.30.0 +version=1.31.0 gnsp.disableApplyOnlyOnRootProjectEnforcement=true From 5bbd8037a77d7abf008a6da735db601a268095ec Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Tue, 22 Mar 2022 16:04:47 +0200 Subject: [PATCH 057/150] Remove jcenter --- build.gradle | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 4a3b9f77..7fff49dc 100644 --- a/build.gradle +++ b/build.gradle @@ -3,7 +3,6 @@ import groovy.json.JsonSlurper allprojects { repositories { - jcenter() mavenCentral() } @@ -41,4 +40,4 @@ tasks.create('createTestSubAccount') { println("Test sub-account created succesfully!") } -} \ No newline at end of file +} From 14c0d95803dbc2cc067cdefafe5a49a95a7c8190 Mon Sep 17 00:00:00 2001 From: Yomes <1785648+YomesInc@users.noreply.github.com> Date: Tue, 22 Mar 2022 17:05:27 +0300 Subject: [PATCH 058/150] Validate auth token --- .../main/java/com/cloudinary/AuthToken.java | 28 +++++++++++---- .../java/com/cloudinary/AuthTokenTest.java | 34 +++++++++++++++++++ .../com/cloudinary/test/CloudinaryTest.java | 3 ++ 3 files changed, 58 insertions(+), 7 deletions(-) diff --git a/cloudinary-core/src/main/java/com/cloudinary/AuthToken.java b/cloudinary-core/src/main/java/com/cloudinary/AuthToken.java index c12698ad..aa8cf213 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/AuthToken.java +++ b/cloudinary-core/src/main/java/com/cloudinary/AuthToken.java @@ -29,7 +29,7 @@ public class AuthToken { private long startTime; private long expiration; private String ip; - private String acl; + private List acl = new ArrayList<>(); private long duration; private boolean isNullToken = false; private static final Pattern UNSAFE_URL_CHARS_PATTERN = Pattern.compile("[ \"#%&'/:;<=>?@\\[\\\\\\]^`{|}~]"); @@ -53,7 +53,16 @@ public AuthToken(Map options) { this.startTime = ObjectUtils.asLong(options.get("startTime"), 0L); this.expiration = ObjectUtils.asLong(options.get("expiration"), 0L); this.ip = (String) options.get("ip"); - this.acl = (String) options.get("acl"); + + Object acl = options.get("acl"); + if (acl != null) { + if (acl instanceof String) { + this.acl = Collections.singletonList(acl.toString()); + } else if (Collection.class.isAssignableFrom(acl.getClass())) { + this.acl = new ArrayList((Collection)acl); + } + } + this.duration = ObjectUtils.asLong(options.get("duration"), 0L); } } @@ -122,8 +131,8 @@ public AuthToken ip(String ip) { * @param acl * @return this */ - public AuthToken acl(String acl) { - this.acl = acl; + public AuthToken acl(String... acl) { + this.acl = Arrays.asList(acl); return this; } @@ -155,6 +164,11 @@ public String generate() { * @return a URL token */ public String generate(String url) { + + if (url == null && (acl == null || acl.size() == 0)) { + throw new IllegalArgumentException("Must provide acl or url"); + } + long expiration = this.expiration; if (expiration == 0) { if (duration > 0) { @@ -172,11 +186,11 @@ public String generate(String url) { tokenParts.add("st=" + startTime); } tokenParts.add("exp=" + expiration); - if (acl != null) { - tokenParts.add("acl=" + escapeToLower(acl)); + if (acl != null && acl.size() > 0) { + tokenParts.add("acl=" + escapeToLower(String.join("!", acl))); } ArrayList toSign = new ArrayList(tokenParts); - if (url != null && acl == null) { + if (url != null && (acl == null || acl.size() == 0)) { toSign.add("url=" + escapeToLower(url)); } String auth = digest(StringUtils.join(toSign, "~")); diff --git a/cloudinary-core/src/test/java/com/cloudinary/AuthTokenTest.java b/cloudinary-core/src/test/java/com/cloudinary/AuthTokenTest.java index 800fc581..8f3a9f75 100644 --- a/cloudinary-core/src/test/java/com/cloudinary/AuthTokenTest.java +++ b/cloudinary-core/src/test/java/com/cloudinary/AuthTokenTest.java @@ -1,7 +1,11 @@ package com.cloudinary; import com.cloudinary.utils.Analytics; +import com.cloudinary.utils.ObjectUtils; + +import org.hamcrest.CoreMatchers; import org.hamcrest.Matchers; +import org.junit.Assert; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -9,6 +13,8 @@ import java.io.UnsupportedEncodingException; import java.util.Calendar; +import java.util.Collections; +import java.util.Map; import java.util.TimeZone; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -127,4 +133,32 @@ public void testIgnoreUrlIfAclIsProvided() { String cookieAclToken = aclToken.generate("http://res.cloudinary.com/test123/image/upload/v1486020273/sample.jpg"); assertEquals(cookieToken, cookieAclToken); } + + @Test + public void testMultiplePatternsInAcl() { + AuthToken token = new AuthToken(KEY).duration(3600).acl("/image/authenticated/*", "/image2/authenticated/*", "/image3/authenticated/*").startTime(22222222); + String cookieToken = token.generate(); + Assert.assertThat(cookieToken, CoreMatchers.containsString("~acl=%2fimage%2fauthenticated%2f*!%2fimage2%2fauthenticated%2f*!%2fimage3%2fauthenticated%2f*~")); + } + + @Test + public void testPublicAclInitializationFromMap() { + Map options = ObjectUtils.asMap( + "acl", Collections.singleton("foo"), + "expiration", 100, + "key", KEY, + "tokenName", "token"); + String token = new AuthToken(options).generate(); + assertEquals("token=exp=100~acl=foo~hmac=88be250f3a912add862959076ee74f392fa0959a953fddd9128787d5c849efd9", token); + } + + @Test(expected = IllegalArgumentException.class) + public void testMissingAclAndUrlShouldThrow() { + String token = new AuthToken(KEY).duration(300).generate(); + } + + @Test + public void testMissingUrlNotMissingAclShouldNotThrow() { + String token = new AuthToken(KEY).duration(300).generate("http://res.cloudinary.com/test123"); + } } diff --git a/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java b/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java index f4f94c43..763cb286 100644 --- a/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java +++ b/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java @@ -18,6 +18,7 @@ import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.lang.reflect.Type; +import java.lang.reflect.ParameterizedType; import java.net.URI; import java.net.URISyntaxException; import java.net.URLDecoder; @@ -1468,6 +1469,8 @@ private void setRandomValue(Random rand, Field field, Object instance) throws Il field.set(instance, rand.nextInt()); } else if (fieldType.equals(long.class) || fieldType.equals(Long.class)) { field.set(instance, rand.nextLong()); + } else if (field.get(instance) instanceof List) { + field.set(instance, Collections.singletonList(cloudinary.randomPublicId())); } else if (fieldType.equals(String.class)) { field.set(instance, cloudinary.randomPublicId()); } else if (fieldType.equals(AuthToken.class)) { From ff53df7eb5b063d4f85011b5e6b6da023f3de717 Mon Sep 17 00:00:00 2001 From: Yomes <1785648+YomesInc@users.noreply.github.com> Date: Tue, 22 Mar 2022 17:56:28 +0300 Subject: [PATCH 059/150] Tests that rely on addons should not run by default --- .../com/cloudinary/test/AbstractApiTest.java | 3 ++- .../com/cloudinary/test/MockableTest.java | 22 +++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java index d950ac6f..d31cd689 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java @@ -608,7 +608,8 @@ public void testManualModeration() throws Exception { } @Test - public void testOcrUpdate() { + public void testOcrUpdate() throws Exception { + assumeAddonEnabled("ocr"); Exception expected = null; // should support requesting ocr info try { diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/MockableTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/MockableTest.java index 18043d3e..c68a4131 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/MockableTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/MockableTest.java @@ -4,7 +4,11 @@ import com.cloudinary.utils.ObjectUtils; import com.cloudinary.utils.StringUtils; +import static org.junit.Assume.assumeTrue; + import java.io.IOException; +import java.util.Arrays; +import java.util.List; import java.util.Map; import java.util.Random; @@ -36,4 +40,22 @@ protected Map preloadResource(Map options) throws IOException { combinedOptions.putAll(options); return cloudinary.uploader().upload("http://res.cloudinary.com/demo/image/upload/sample", combinedOptions); } + + private static final List enabledAddons = getEnabledAddons(); + + protected void assumeAddonEnabled(String addon) throws Exception { + boolean enabled = enabledAddons.contains(addon.toLowerCase()) + || (enabledAddons.size() == 1 && enabledAddons.get(0).equalsIgnoreCase("all")); + + assumeTrue(String.format("Use CLD_TEST_ADDONS environment variable to enable tests for %s.", addon), enabled); + } + + private static List getEnabledAddons() { + String envAddons = System.getenv() + .getOrDefault("CLD_TEST_ADDONS", "") + .toLowerCase() + .replaceAll("\\s", ""); + + return Arrays.asList(envAddons.split(",")); + } } From 8f222040921c2f11e9eb343f26784340698dbb12 Mon Sep 17 00:00:00 2001 From: daplf Date: Tue, 22 Mar 2022 14:57:43 +0000 Subject: [PATCH 060/150] Fix `verifySignature` timestamp units --- .../api/signing/NotificationRequestSignatureVerifier.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cloudinary-core/src/main/java/com/cloudinary/api/signing/NotificationRequestSignatureVerifier.java b/cloudinary-core/src/main/java/com/cloudinary/api/signing/NotificationRequestSignatureVerifier.java index 62ad579b..1b5d3e89 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/api/signing/NotificationRequestSignatureVerifier.java +++ b/cloudinary-core/src/main/java/com/cloudinary/api/signing/NotificationRequestSignatureVerifier.java @@ -54,7 +54,7 @@ public boolean verifySignature(String body, String timestamp, String signature) * * @param body notification message body, represented as string * @param timestamp value of X-Cld-Timestamp custom HTTP header of notification message, representing notification - * issue timestamp + * issue timestamp in seconds * @param signature actual signature value, usually passed via X-Cld-Signature custom HTTP header of notification * message * @param secondsValidFor the amount of time, in seconds, the notification message is considered valid by client @@ -69,7 +69,7 @@ public boolean verifySignature(String body, String timestamp, String signature, } return verifySignature(body, timestamp, signature) && - (System.currentTimeMillis() - parsedTimestamp <= secondsValidFor * 1000L); + (System.currentTimeMillis() / 1000L - parsedTimestamp <= secondsValidFor); } } From d5d21a87b4f06ed704aaa25fb53e674fbf6707ff Mon Sep 17 00:00:00 2001 From: Yomes <1785648+YomesInc@users.noreply.github.com> Date: Tue, 22 Mar 2022 17:58:12 +0300 Subject: [PATCH 061/150] Support metadata fields reordering --- .../src/main/java/com/cloudinary/Api.java | 23 +++++++++++++ .../test/AbstractStructuredMetadataTest.java | 34 +++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/cloudinary-core/src/main/java/com/cloudinary/Api.java b/cloudinary-core/src/main/java/com/cloudinary/Api.java index 990ecc2d..3400364a 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Api.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Api.java @@ -710,6 +710,29 @@ public ApiResponse deleteMetadataField(String fieldExternalId) throws Exception return callApi(HttpMethod.DELETE, uri, Collections.emptyMap(), Collections.emptyMap()); } + /** + * Reorders metadata fields. + * + * @param orderBy Criteria for the order (one of the fields 'label', 'external_id', 'created_at') + * @param direction Optional (gets either asc or desc) + * @param options Additional options + * @return List of metadata fields in their new order + * @throws Exception + */ + public ApiResponse reorderMetadataFields(String orderBy, String direction, Map options) throws Exception { + if (orderBy == null) { + throw new IllegalArgumentException("Must supply orderBy"); + } + + List uri = Arrays.asList("metadata_fields", "order"); + Map map = ObjectUtils.asMap("order_by", orderBy); + if (direction != null) { + map.put("direction", direction); + } + + return callApi(HttpMethod.PUT, uri, map, options); + } + private Map extractParams(Map options, List keys) { Map result = new HashMap(); for (String key : keys) { diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractStructuredMetadataTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractStructuredMetadataTest.java index 7b06c557..48c60bc3 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractStructuredMetadataTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractStructuredMetadataTest.java @@ -5,6 +5,8 @@ import com.cloudinary.api.ApiResponse; import com.cloudinary.api.exceptions.BadRequest; import com.cloudinary.metadata.*; + +import org.hamcrest.Matchers; import org.junit.*; import org.junit.rules.TestName; @@ -172,6 +174,38 @@ public void testRestoreDatasourceEntries() throws Exception { assertNotNull(result); } + @Test + public void testReorderMetadataFieldsByLabel() throws Exception { + AddStringField("some_value"); + AddStringField("aaa"); + AddStringField("zzz"); + + ApiResponse result = api.reorderMetadataFields("label", null, Collections.EMPTY_MAP); + assertThat(getField(result, 0), Matchers.containsString("aaa")); + + result = api.reorderMetadataFields("label", "desc", Collections.EMPTY_MAP); + assertThat(getField(result, 0), Matchers.containsString("zzz")); + + result = api.reorderMetadataFields("label", "asc", Collections.EMPTY_MAP); + assertThat(getField(result, 0), Matchers.containsString("aaa")); + } + + @Test(expected = IllegalArgumentException.class) + public void testReorderMetadataFieldsOrderByIsRequired() throws Exception { + api.reorderMetadataFields(null, null, Collections.EMPTY_MAP); + } + + private String getField(ApiResponse result, int index) { + String actual = ((Map)((ArrayList)result.get("metadata_fields")).get(index)).get("label").toString(); + return actual; + } + + private void AddStringField(String labelPrefix) throws Exception { + StringMetadataField field = newFieldInstance(labelPrefix); + ApiResponse fieldResult = addFieldToAccount(field); + String fieldId = fieldResult.get("external_id").toString(); + } + @Test public void testUploadWithMetadata() throws Exception { StringMetadataField field = newFieldInstance("testUploadWithMetadata"); From c287a620eaf5056d430498462652224f82d50a0e Mon Sep 17 00:00:00 2001 From: Yomes <1785648+YomesInc@users.noreply.github.com> Date: Tue, 22 Mar 2022 17:58:58 +0300 Subject: [PATCH 062/150] Search by asset id --- .../java/com/cloudinary/test/AbstractSearchTest.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractSearchTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractSearchTest.java index 212b15e3..be97f3f9 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractSearchTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractSearchTest.java @@ -21,6 +21,7 @@ abstract public class AbstractSearchTest extends MockableTest { private static final String SEARCH_TEST = "search_test_" + SUFFIX; private static final String SEARCH_TEST_1 = SEARCH_TEST + "_1"; private static final String SEARCH_TEST_2 = SEARCH_TEST + "_2"; + private static String SEARCH_TEST_ASSET_ID_1; @BeforeClass public static void setUpClass() throws Exception { @@ -29,7 +30,7 @@ public static void setUpClass() throws Exception { cloudinary.api().deleteResourcesByTag(SEARCH_TAG, null); cloudinary.uploader().upload(SRC_TEST_IMAGE, options); options = ObjectUtils.asMap("public_id", SEARCH_TEST_1, "tags", UPLOAD_TAGS, "context", "stage=new"); - cloudinary.uploader().upload(SRC_TEST_IMAGE, options); + SEARCH_TEST_ASSET_ID_1 = cloudinary.uploader().upload(SRC_TEST_IMAGE, options).get("asset_id").toString(); options = ObjectUtils.asMap("public_id", SEARCH_TEST_2, "tags", UPLOAD_TAGS, "context", "stage=validated"); cloudinary.uploader().upload(SRC_TEST_IMAGE, options); try { @@ -66,6 +67,13 @@ public void shouldFindResourceByPublicId() throws Exception { assertEquals(1, resources.size()); } + @Test + public void shouldFindResourceByAssetId() throws Exception { + Map result = cloudinary.search().expression(String.format("asset_id:%s", SEARCH_TEST_ASSET_ID_1)).execute(); + List resources = (List) result.get("resources"); + assertEquals(1, resources.size()); + } + @Test public void shouldPaginateResourcesLimitedByTagAndOrderdByAscendingPublicId() throws Exception { List resources; From 65fd1e32dd130959ad860779d384d233682b5f0f Mon Sep 17 00:00:00 2001 From: Yomes <1785648+YomesInc@users.noreply.github.com> Date: Tue, 22 Mar 2022 17:59:24 +0300 Subject: [PATCH 063/150] Get the details of a single resource by asset_id --- cloudinary-core/src/main/java/com/cloudinary/Api.java | 6 ++++++ .../src/main/java/com/cloudinary/test/AbstractApiTest.java | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/cloudinary-core/src/main/java/com/cloudinary/Api.java b/cloudinary-core/src/main/java/com/cloudinary/Api.java index 3400364a..200000b0 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Api.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Api.java @@ -115,6 +115,12 @@ public ApiResponse resourcesByContext(String key, String value, Map options) thr return callApi(HttpMethod.GET, Arrays.asList("resources", resourceType, "context"), params, options); } + public ApiResponse resourceByAssetID(String assetId, Map options) throws Exception { + if (options == null) options = ObjectUtils.emptyMap(); + Map params = ObjectUtils.only(options, "tags", "context", "moderations"); + ApiResponse response = callApi(HttpMethod.GET, Arrays.asList("resources", assetId), params, options); + return response; + } public ApiResponse resourcesByAssetIDs(Iterable assetIds, Map options) throws Exception { if (options == null) options = ObjectUtils.emptyMap(); Map params = ObjectUtils.only(options, "public_ids", "tags", "context", "moderations"); diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java index d31cd689..f99ec8f0 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java @@ -280,6 +280,12 @@ public void testResourcesByAssetIds() throws Exception { assertNotNull(findByAttr(resources, "public_id", API_TEST_1)); } + @Test + public void testResourceByAssetId() throws Exception { + Map result = api.resourceByAssetID(assetId1, ObjectUtils.asMap("tags", true, "context", true)); + assertEquals(API_TEST, result.get("public_id").toString()); + } + @Test public void testResourcesByPublicIds() throws Exception { // should allow listing resources by public ids From 97e47c103160049ddbaf24b01ad7815b0e486bc3 Mon Sep 17 00:00:00 2001 From: Yomes <1785648+YomesInc@users.noreply.github.com> Date: Tue, 22 Mar 2022 18:01:13 +0300 Subject: [PATCH 064/150] Support start offset and end offset in variable materialization --- .../java/com/cloudinary/Transformation.java | 4 +- .../com/cloudinary/TransformationTest.java | 69 +++++++++++++++++++ 2 files changed, 71 insertions(+), 2 deletions(-) diff --git a/cloudinary-core/src/main/java/com/cloudinary/Transformation.java b/cloudinary-core/src/main/java/com/cloudinary/Transformation.java index 8b3d8c40..c4b2ca9e 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Transformation.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Transformation.java @@ -785,7 +785,7 @@ public String generate(Map options) { } if (!components.isEmpty()) { final String joined = StringUtils.join(components, ","); - transformations.add(Expression.normalize(joined)); + transformations.add(joined); } if (isResponsive) { @@ -894,7 +894,7 @@ private static String normRangeValue(Object objectValue) { Matcher matcher = RANGE_VALUE_RE.matcher(value); if (!matcher.matches()) { - return null; + return Expression.normalize(value); } String modifier = ""; diff --git a/cloudinary-core/src/test/java/com/cloudinary/TransformationTest.java b/cloudinary-core/src/test/java/com/cloudinary/TransformationTest.java index 2ff10486..200efc14 100644 --- a/cloudinary-core/src/test/java/com/cloudinary/TransformationTest.java +++ b/cloudinary-core/src/test/java/com/cloudinary/TransformationTest.java @@ -4,9 +4,14 @@ import com.cloudinary.transformation.TextLayer; import com.cloudinary.utils.ObjectUtils; import org.cloudinary.json.JSONArray; +import org.hamcrest.CoreMatchers; import org.junit.After; import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; + +import junitparams.JUnitParamsRunner; +import junitparams.Parameters; import java.util.*; @@ -18,6 +23,7 @@ * */ @SuppressWarnings("unchecked") +@RunWith(JUnitParamsRunner.class) public class TransformationTest { @Before @@ -300,4 +306,67 @@ public void testContextMetadataToUserVariables() { assertEquals("$xpos_ctx:!x_pos!_to_f,$ypos_ctx:!y_pos!_to_f,c_crop,x_$xpos_mul_w,y_$ypos_mul_h", t.generate()); } + + @Parameters({ "angle", + "aspect_ratio", + "dpr", + "effect", + "height", + "opacity", + "quality", + "width", + "x", + "y", + "end_offset", + "start_offset", + "zoom" }) + @Test + public void testVerifyNormalizationShouldNormalize(String input) throws Exception { + String t = new Transformation().param(input, "width * 2").generate(); + assertThat(t, CoreMatchers.containsString("w_mul_2")); + } + + @Parameters({ + "audio_codec", + "audio_frequency", + "border", + "bit_rate", + "color_space", + "default_image", + "delay", + "density", + "fetch_format", + "custom_function", + "fps", + "gravity", + "overlay", + "prefix", + "page", + "underlay", + "video_sampling", + "streaming_profile", + "keyframe_interval"}) + @Test + public void test1VerifyNormalizationShouldNotNormalize(String input) throws Exception { + String t = new Transformation().param(input, "width * 2").generate(); + assertThat(t, CoreMatchers.not(CoreMatchers.containsString("w_mul_2"))); + } + + @Test + public void testSupportStartOffset() throws Exception { + String t = new Transformation().width(100).startOffset("idu - 5").generate(); + assertThat(t, CoreMatchers.containsString("so_idu_sub_5")); + + t = new Transformation().width(100).startOffset("$logotime").generate(); + assertThat(t, CoreMatchers.containsString("so_$logotime")); + } + + @Test + public void testSupportEndOffset() throws Exception { + String t = new Transformation().width(100).endOffset("idu - 5").generate(); + assertThat(t, CoreMatchers.containsString("eo_idu_sub_5")); + + t = new Transformation().width(100).endOffset("$logotime").generate(); + assertThat(t, CoreMatchers.containsString("eo_$logotime")); + } } From 6297083be37d91f1415f36edb06885b446317e41 Mon Sep 17 00:00:00 2001 From: Yomes <1785648+YomesInc@users.noreply.github.com> Date: Tue, 22 Mar 2022 19:38:02 +0300 Subject: [PATCH 065/150] Verify expression normalization --- .../src/main/java/com/cloudinary/Transformation.java | 1 + .../src/test/java/com/cloudinary/TransformationTest.java | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/cloudinary-core/src/main/java/com/cloudinary/Transformation.java b/cloudinary-core/src/main/java/com/cloudinary/Transformation.java index c4b2ca9e..eaf2f4a9 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Transformation.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Transformation.java @@ -748,6 +748,7 @@ public String generate(Map options) { params.put("a", Expression.normalize(angle)); params.put("ar", Expression.normalize(options.get("aspect_ratio"))); + params.put("iar", Expression.normalize(options.get("initial_aspect_ratio"))); params.put("b", background); params.put("c", crop); params.put("co", color); diff --git a/cloudinary-core/src/test/java/com/cloudinary/TransformationTest.java b/cloudinary-core/src/test/java/com/cloudinary/TransformationTest.java index 200efc14..66244e9a 100644 --- a/cloudinary-core/src/test/java/com/cloudinary/TransformationTest.java +++ b/cloudinary-core/src/test/java/com/cloudinary/TransformationTest.java @@ -306,7 +306,7 @@ public void testContextMetadataToUserVariables() { assertEquals("$xpos_ctx:!x_pos!_to_f,$ypos_ctx:!y_pos!_to_f,c_crop,x_$xpos_mul_w,y_$ypos_mul_h", t.generate()); } - + @Parameters({ "angle", "aspect_ratio", "dpr", @@ -347,7 +347,7 @@ public void testVerifyNormalizationShouldNormalize(String input) throws Exceptio "streaming_profile", "keyframe_interval"}) @Test - public void test1VerifyNormalizationShouldNotNormalize(String input) throws Exception { + public void testVerifyNormalizationShouldNotNormalize(String input) throws Exception { String t = new Transformation().param(input, "width * 2").generate(); assertThat(t, CoreMatchers.not(CoreMatchers.containsString("w_mul_2"))); } From bec0c3b28a87a2b8d0febfc7e9b3f3d92c6391a6 Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Wed, 23 Mar 2022 16:34:45 +0200 Subject: [PATCH 066/150] bump versions --- cloudinary-http43/build.gradle | 2 +- samples/photo_album/pom.xml | 4 ++-- samples/photo_album_gae/pom.xml | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cloudinary-http43/build.gradle b/cloudinary-http43/build.gradle index 6b22abc2..23942327 100644 --- a/cloudinary-http43/build.gradle +++ b/cloudinary-http43/build.gradle @@ -20,7 +20,7 @@ task ciTest( type: Test ) { dependencies { compile project(':cloudinary-core') compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.1' - compile group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.3' + compile group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.3.1' compile group: 'org.apache.httpcomponents', name: 'httpmime', version: '4.3' testCompile project(':cloudinary-test-common') testCompile group: 'org.hamcrest', name: 'java-hamcrest', version: '2.0.0.0' diff --git a/samples/photo_album/pom.xml b/samples/photo_album/pom.xml index d38291c5..b6210d57 100644 --- a/samples/photo_album/pom.xml +++ b/samples/photo_album/pom.xml @@ -8,7 +8,7 @@ photo_album - 4.3.10.RELEASE + 5.3.0 @@ -108,7 +108,7 @@ commons-fileupload commons-fileupload - 1.3 + 1.3.3 diff --git a/samples/photo_album_gae/pom.xml b/samples/photo_album_gae/pom.xml index f6d84dad..f95b9dc3 100644 --- a/samples/photo_album_gae/pom.xml +++ b/samples/photo_album_gae/pom.xml @@ -8,7 +8,7 @@ photo_album_gae - 3.2.16.RELEASE + 5.3.0 1 1.9.37 UTF-8 @@ -111,7 +111,7 @@ commons-fileupload commons-fileupload - 1.3 + 1.3.3 From 94092782ce64bd48519b782de52d52b291d00e39 Mon Sep 17 00:00:00 2001 From: Yomes <1785648+YomesInc@users.noreply.github.com> Date: Wed, 23 Mar 2022 17:35:19 +0300 Subject: [PATCH 067/150] Upload APIs rename call should return metadata and context --- .../main/java/com/cloudinary/Uploader.java | 2 ++ .../test/AbstractStructuredMetadataTest.java | 9 ++----- .../cloudinary/test/AbstractUploaderTest.java | 25 +++++++++++++++++++ .../cloudinary/test/MetadataTestHelper.java | 24 ++++++++++++++++++ 4 files changed, 53 insertions(+), 7 deletions(-) create mode 100644 cloudinary-test-common/src/main/java/com/cloudinary/test/MetadataTestHelper.java diff --git a/cloudinary-core/src/main/java/com/cloudinary/Uploader.java b/cloudinary-core/src/main/java/com/cloudinary/Uploader.java index 0531161e..e9a6909a 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Uploader.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Uploader.java @@ -247,6 +247,8 @@ public Map rename(String fromPublicId, String toPublicId, Map options) throws IO params.put("to_public_id", toPublicId); params.put("invalidate", ObjectUtils.asBoolean(options.get("invalidate"), false).toString()); params.put("to_type", options.get("to_type")); + params.put("context", ObjectUtils.asBoolean(options.get("context"), false).toString()); + params.put("metadata", ObjectUtils.asBoolean(options.get("metadata"), false).toString()); return callApi("rename", params, options, null); } diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractStructuredMetadataTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractStructuredMetadataTest.java index 48c60bc3..9aefb64b 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractStructuredMetadataTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractStructuredMetadataTest.java @@ -302,17 +302,12 @@ private SetMetadataField createSetField(String labelPrefix) { } private StringMetadataField newFieldInstance(String labelPrefix) throws Exception { - StringMetadataField field = new StringMetadataField(); String label = labelPrefix + "_" + SUFFIX; - field.setLabel(label); - field.setMandatory(true); - field.setValidation(new MetadataValidation.StringLength(3, 9)); - field.setDefaultValue("val_test"); - return field; + return MetadataTestHelper.newFieldInstance(label); } private ApiResponse addFieldToAccount(MetadataField field) throws Exception { - ApiResponse apiResponse = api.addMetadataField(field); + ApiResponse apiResponse = MetadataTestHelper.addFieldToAccount(api, field); metadataFieldExternalIds.add(apiResponse.get("external_id").toString()); return apiResponse; } diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java index bfce72dd..79046890 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java @@ -219,6 +219,31 @@ public void testRename() throws Exception { assertEquals(cloudinary.api().resource(publicId2, ObjectUtils.emptyMap()).get("format"), "ico"); } + @Test + public void testRenameShouldReturnContext() throws Exception { + Map result = cloudinary.uploader().upload(SRC_TEST_IMAGE, asMap("tags", Arrays.asList(SDK_TEST_TAG, UPLOADER_TAG), "context", asMap("foo", "boo"))); + + String publicId = result.get("public_id").toString(); + String publicId2 = "folder/" + publicId + "2"; + Map renameResult = cloudinary.uploader().rename(publicId, publicId2, asMap("context", true)); + assertNotNull(renameResult.get("context")); + } + + @Test + public void testRenameShouldReturnMetadata() throws Exception { + String label = "test" + SUFFIX; + StringMetadataField f = MetadataTestHelper.newFieldInstance(label); + Map fieldResult = MetadataTestHelper.addFieldToAccount(cloudinary.api(), f); + String fieldId = fieldResult.get("external_id").toString(); + Map metadata = Collections.singletonMap(fieldId, "123456"); + Map result = cloudinary.uploader().upload(SRC_TEST_IMAGE, asMap("tags", Arrays.asList(SDK_TEST_TAG, UPLOADER_TAG), "metadata", metadata)); + + String publicId = result.get("public_id").toString(); + String publicId2 = "folder/" + publicId + "2"; + Map renameResult = cloudinary.uploader().rename(publicId, publicId2, asMap("metadata", true)); + assertNotNull(renameResult.get("metadata")); + } + @Test public void testUniqueFilename() throws Exception { Map result = cloudinary.uploader().upload(SRC_TEST_IMAGE, asMap("use_filename", true, "tags", Arrays.asList(SDK_TEST_TAG, UPLOADER_TAG))); diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/MetadataTestHelper.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/MetadataTestHelper.java new file mode 100644 index 00000000..d130b282 --- /dev/null +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/MetadataTestHelper.java @@ -0,0 +1,24 @@ +package com.cloudinary.test; + +import com.cloudinary.Api; +import com.cloudinary.api.ApiResponse; +import com.cloudinary.metadata.MetadataField; +import com.cloudinary.metadata.MetadataValidation; +import com.cloudinary.metadata.StringMetadataField; + +public class MetadataTestHelper { + public static StringMetadataField newFieldInstance(String label) throws Exception { + StringMetadataField field = new StringMetadataField(); + field.setLabel(label); + field.setMandatory(true); + field.setValidation(new MetadataValidation.StringLength(3, 9)); + field.setDefaultValue("val_test"); + return field; + } + + public static ApiResponse addFieldToAccount(Api api, MetadataField field) throws Exception { + ApiResponse apiResponse = api.addMetadataField(field); + return apiResponse; + } +} + From ff4fd2ed26430b30a578d6b36056254770a72eec Mon Sep 17 00:00:00 2001 From: francistagbo <61406266+francistagbo@users.noreply.github.com> Date: Wed, 23 Mar 2022 23:04:19 +0200 Subject: [PATCH 068/150] Remove duplicates in Search Api fields --- .../src/main/java/com/cloudinary/Search.java | 16 +++++-- .../cloudinary/test/AbstractSearchTest.java | 44 ++++++++++++++++--- 2 files changed, 52 insertions(+), 8 deletions(-) diff --git a/cloudinary-core/src/main/java/com/cloudinary/Search.java b/cloudinary-core/src/main/java/com/cloudinary/Search.java index dc2f8a96..f16be7eb 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Search.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Search.java @@ -40,18 +40,28 @@ public Search nextCursor(String value) { } public Search aggregate(String field) { - aggregateParam.add(field); + if (!aggregateParam.contains(field)) { + aggregateParam.add(field); + } return this; } public Search withField(String field) { - withFieldParam.add(field); + if (!withFieldParam.contains(field)) { + withFieldParam.add(field); + } return this; } public Search sortBy(String field, String dir) { HashMap sortBucket = new HashMap(); sortBucket.put(field, dir); + for (int i = 0; i < sortByParam.size(); i++) { + if (sortByParam.get(i).containsKey(field)){ + sortByParam.add(i, sortBucket); + return this; + } + } sortByParam.add(sortBucket); return this; } @@ -68,4 +78,4 @@ public ApiResponse execute() throws Exception { Map options = ObjectUtils.asMap("content_type", "json"); return this.api.callApi(Api.HttpMethod.POST, Arrays.asList("resources", "search"), this.toQuery(), options); } -} \ No newline at end of file +} diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractSearchTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractSearchTest.java index be97f3f9..67d62967 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractSearchTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractSearchTest.java @@ -1,15 +1,15 @@ package com.cloudinary.test; import com.cloudinary.Cloudinary; +import com.cloudinary.Search; import com.cloudinary.utils.ObjectUtils; import org.junit.*; import org.junit.rules.TestName; -import java.util.List; -import java.util.Map; +import java.lang.reflect.Field; +import java.util.*; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; +import static org.junit.Assert.*; import static org.junit.Assume.assumeNotNull; @SuppressWarnings({"rawtypes", "unchecked", "JavaDoc"}) @@ -74,12 +74,46 @@ public void shouldFindResourceByAssetId() throws Exception { assertEquals(1, resources.size()); } + @Test + public void testShouldNotDuplicateValues() throws Exception { + Search request = cloudinary.search().maxResults(1). + sortBy("created_at", "asc") + .sortBy("created_at", "desc") + .sortBy("public_id", "asc") + .aggregate("format") + .aggregate("format") + .aggregate("resource_type") + .withField("context") + .withField("context") + .withField("tags"); + Field[] fields = Search.class.getDeclaredFields(); + for(Field field : fields) { + if(field.getName() == "aggregateParam") { + field.setAccessible(true); + ArrayList aggregateList = (ArrayList) field.get(request); + Set testSet = new HashSet(aggregateList); + assertTrue(aggregateList.size() == testSet.size()); + } + if (field.getName() == "withFieldParam") { + field.setAccessible(true); + ArrayList withFieldList = (ArrayList) field.get(request); + Set testSet = new HashSet(withFieldList); + assertTrue(withFieldList.size() == testSet.size()); + } + if (field.getName() == "sortByParam") { + field.setAccessible(true); + ArrayList> sortByList = (ArrayList>) field.get(request); + Set> testSet = new HashSet>(sortByList); + assertTrue(sortByList.size() == testSet.size()); + } + } + } + @Test public void shouldPaginateResourcesLimitedByTagAndOrderdByAscendingPublicId() throws Exception { List resources; Map result = cloudinary.search().maxResults(1).expression(String.format("tags:%s", SEARCH_TAG)).sortBy("public_id", "asc").execute(); resources = (List) result.get("resources"); - assertEquals(1, resources.size()); assertEquals(3, result.get("total_count")); assertEquals(SEARCH_TEST, resources.get(0).get("public_id")); From 046777f5702e452fa7b620890f71fa2505860c84 Mon Sep 17 00:00:00 2001 From: adimiz1 Date: Thu, 24 Mar 2022 11:08:24 +0200 Subject: [PATCH 069/150] Remove iar from transfomration params --- cloudinary-core/src/main/java/com/cloudinary/Transformation.java | 1 - 1 file changed, 1 deletion(-) diff --git a/cloudinary-core/src/main/java/com/cloudinary/Transformation.java b/cloudinary-core/src/main/java/com/cloudinary/Transformation.java index eaf2f4a9..c4b2ca9e 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Transformation.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Transformation.java @@ -748,7 +748,6 @@ public String generate(Map options) { params.put("a", Expression.normalize(angle)); params.put("ar", Expression.normalize(options.get("aspect_ratio"))); - params.put("iar", Expression.normalize(options.get("initial_aspect_ratio"))); params.put("b", background); params.put("c", crop); params.put("co", color); From e47e686908d4ea98a0736da690bdeee703d7f87c Mon Sep 17 00:00:00 2001 From: Yomes <1785648+YomesInc@users.noreply.github.com> Date: Wed, 30 Mar 2022 14:45:22 +0300 Subject: [PATCH 070/150] Support structured metadata in `resources` api call --- .../src/main/java/com/cloudinary/Api.java | 8 ++-- .../com/cloudinary/test/AbstractApiTest.java | 42 +++++++++++++++++++ 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/cloudinary-core/src/main/java/com/cloudinary/Api.java b/cloudinary-core/src/main/java/com/cloudinary/Api.java index 200000b0..74dd6bbc 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Api.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Api.java @@ -88,7 +88,7 @@ public ApiResponse resources(Map options) throws Exception { if (type != null) uri.add(type); - ApiResponse response = callApi(HttpMethod.GET, uri, ObjectUtils.only(options, "next_cursor", "direction", "max_results", "prefix", "tags", "context", "moderations", "start_at"), options); + ApiResponse response = callApi(HttpMethod.GET, uri, ObjectUtils.only(options, "next_cursor", "direction", "max_results", "prefix", "tags", "context", "moderations", "start_at", "metadata"), options); return response; } @@ -96,7 +96,7 @@ public ApiResponse resourcesByTag(String tag, Map options) throws Exception { if (options == null) options = ObjectUtils.emptyMap(); String resourceType = ObjectUtils.asString(options.get("resource_type"), "image"); - ApiResponse response = callApi(HttpMethod.GET, Arrays.asList("resources", resourceType, "tags", tag), ObjectUtils.only(options, "next_cursor", "direction", "max_results", "tags", "context", "moderations"), options); + ApiResponse response = callApi(HttpMethod.GET, Arrays.asList("resources", resourceType, "tags", tag), ObjectUtils.only(options, "next_cursor", "direction", "max_results", "tags", "context", "moderations", "metadata"), options); return response; } @@ -107,7 +107,7 @@ public ApiResponse resourcesByContext(String key, 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"); + Map params = ObjectUtils.only(options, "next_cursor", "direction", "max_results", "tags", "context", "moderations", "metadata"); params.put("key", key); if (StringUtils.isNotBlank(value)) { params.put("value", value); @@ -143,7 +143,7 @@ public ApiResponse resourcesByModeration(String kind, String status, Map options if (options == null) options = ObjectUtils.emptyMap(); String resourceType = ObjectUtils.asString(options.get("resource_type"), "image"); - ApiResponse response = callApi(HttpMethod.GET, Arrays.asList("resources", resourceType, "moderations", kind, status), ObjectUtils.only(options, "next_cursor", "direction", "max_results", "tags", "context", "moderations"), options); + ApiResponse response = callApi(HttpMethod.GET, Arrays.asList("resources", resourceType, "moderations", kind, status), ObjectUtils.only(options, "next_cursor", "direction", "max_results", "tags", "context", "moderations", "metadata"), options); return response; } diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java index f99ec8f0..e7cc0f32 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java @@ -4,6 +4,7 @@ import com.cloudinary.api.ApiResponse; import com.cloudinary.api.exceptions.BadRequest; import com.cloudinary.api.exceptions.NotFound; +import com.cloudinary.metadata.StringMetadataField; import com.cloudinary.transformation.TextLayer; import com.cloudinary.utils.ObjectUtils; import org.junit.*; @@ -367,6 +368,47 @@ public void testDeleteDerivedByTransformation() throws Exception { assertTrue(derived.size() == 0); } + @Test + public void testGetResourcesWithMetadata() throws Exception { + String public_id = "api_,withMetadata" + SUFFIX; + String fieldId = MetadataTestHelper.addFieldToAccount(api, MetadataTestHelper.newFieldInstance("some_field" + SUFFIX)).get("external_id").toString(); + cloudinary.uploader().upload(SRC_TEST_IMAGE, + ObjectUtils.asMap("public_id", public_id, + "tags", UPLOAD_TAGS, + "metadata", ObjectUtils.asMap(fieldId, "test"), + "moderation", "manual", + "context", ObjectUtils.asMap("name", "value"))); + + Map result = api.resources(ObjectUtils.asMap("metadata", false)); + assertNull(getMetadata(public_id, result)); + + result = api.resources(ObjectUtils.asMap("metadata", true)); + assertNotNull(getMetadata(public_id, result)); + + result = api.resourcesByTag(UPLOAD_TAGS[0], ObjectUtils.asMap("metadata", true)); + assertNotNull(getMetadata(public_id, result)); + + result = api.resourcesByTag(UPLOAD_TAGS[0], ObjectUtils.asMap("metadata", false)); + assertNull(getMetadata(public_id, result)); + + result = api.resourcesByModeration("manual", "pending", ObjectUtils.asMap("metadata", true)); + assertNotNull(getMetadata(public_id, result)); + + result = api.resourcesByModeration("manual", "pending", ObjectUtils.asMap("metadata", false)); + assertNull(getMetadata(public_id, result)); + + result = api.resourcesByContext("name", "value", ObjectUtils.asMap("metadata", true)); + assertNotNull(getMetadata(public_id, result)); + + result = api.resourcesByContext("name", "value", ObjectUtils.asMap("metadata", false)); + assertNull(getMetadata(public_id, result)); + } + + private Object getMetadata(String public_id, Map result) { + Map resource = findByAttr((List) result.get("resources"), "public_id", public_id); + return resource.get("metadata"); + } + @Test(expected = NotFound.class) public void test09DeleteResources() throws Exception { // should allow deleting resources From cfa2d1082b32d19150e90d3c82f77210cd83971c Mon Sep 17 00:00:00 2001 From: Yomes <1785648+YomesInc@users.noreply.github.com> Date: Wed, 30 Mar 2022 16:39:13 +0300 Subject: [PATCH 071/150] Support multiple acls in cookies --- cloudinary-core/src/test/java/com/cloudinary/AuthTokenTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cloudinary-core/src/test/java/com/cloudinary/AuthTokenTest.java b/cloudinary-core/src/test/java/com/cloudinary/AuthTokenTest.java index 8f3a9f75..ca30479e 100644 --- a/cloudinary-core/src/test/java/com/cloudinary/AuthTokenTest.java +++ b/cloudinary-core/src/test/java/com/cloudinary/AuthTokenTest.java @@ -161,4 +161,6 @@ public void testMissingAclAndUrlShouldThrow() { public void testMissingUrlNotMissingAclShouldNotThrow() { String token = new AuthToken(KEY).duration(300).generate("http://res.cloudinary.com/test123"); } + + } From fd41e665f3bf74980624c7bf94572c3a6754f44f Mon Sep 17 00:00:00 2001 From: Yomes <1785648+YomesInc@users.noreply.github.com> Date: Mon, 4 Apr 2022 12:53:33 +0300 Subject: [PATCH 072/150] Fix transformations API call --- .../src/main/java/com/cloudinary/Api.java | 14 ++++++++++---- .../java/com/cloudinary/EagerTransformation.java | 4 ++-- .../java/com/cloudinary/TransformationTest.java | 9 +++++++++ 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/cloudinary-core/src/main/java/com/cloudinary/Api.java b/cloudinary-core/src/main/java/com/cloudinary/Api.java index 74dd6bbc..ee1123d5 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Api.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Api.java @@ -235,12 +235,15 @@ public ApiResponse transformations(Map options) throws Exception { public ApiResponse transformation(String transformation, Map options) throws Exception { if (options == null) options = ObjectUtils.emptyMap(); - return callApi(HttpMethod.GET, Arrays.asList("transformations", transformation), ObjectUtils.only(options, "next_cursor", "max_results"), options); + Map map = ObjectUtils.only(options, "next_cursor", "max_results"); + map.put("transformation", transformation); + return callApi(HttpMethod.GET, Arrays.asList("transformations"), map, options); } public ApiResponse deleteTransformation(String transformation, Map options) throws Exception { if (options == null) options = ObjectUtils.emptyMap(); - return callApi(HttpMethod.DELETE, Arrays.asList("transformations", transformation), ObjectUtils.emptyMap(), options); + Map updates = ObjectUtils.asMap("transformation", transformation); + return callApi(HttpMethod.DELETE, Arrays.asList("transformations"), updates, options); } // updates - currently only supported update are: @@ -248,11 +251,14 @@ public ApiResponse deleteTransformation(String transformation, Map options) thro // "unsafe_update": transformation string public ApiResponse updateTransformation(String transformation, Map updates, Map options) throws Exception { if (options == null) options = ObjectUtils.emptyMap(); - return callApi(HttpMethod.PUT, Arrays.asList("transformations", transformation), updates, options); + updates.put("transformation", transformation); + return callApi(HttpMethod.PUT, Arrays.asList("transformations"), updates, options); } public ApiResponse createTransformation(String name, String definition, Map options) throws Exception { - return callApi(HttpMethod.POST, Arrays.asList("transformations", name), ObjectUtils.asMap("transformation", definition), options); + return callApi(HttpMethod.POST, + Arrays.asList("transformations"), + ObjectUtils.asMap("transformation", definition, "name", name), options); } public ApiResponse uploadPresets(Map options) throws Exception { diff --git a/cloudinary-core/src/main/java/com/cloudinary/EagerTransformation.java b/cloudinary-core/src/main/java/com/cloudinary/EagerTransformation.java index 29a64228..fc34ee0f 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/EagerTransformation.java +++ b/cloudinary-core/src/main/java/com/cloudinary/EagerTransformation.java @@ -36,7 +36,7 @@ public String generate(Iterable optionsList) { } } - if (StringUtils.isNotBlank(format)){ + if (format != null){ components.add(format); } @@ -48,7 +48,7 @@ public String generate(Map options) { List eager = new ArrayList(); eager.add(super.generate(options)); - if (StringUtils.isNotBlank(format)){ + if (format != null){ eager.add(format); } diff --git a/cloudinary-core/src/test/java/com/cloudinary/TransformationTest.java b/cloudinary-core/src/test/java/com/cloudinary/TransformationTest.java index 66244e9a..1c7f93ba 100644 --- a/cloudinary-core/src/test/java/com/cloudinary/TransformationTest.java +++ b/cloudinary-core/src/test/java/com/cloudinary/TransformationTest.java @@ -307,6 +307,15 @@ public void testContextMetadataToUserVariables() { assertEquals("$xpos_ctx:!x_pos!_to_f,$ypos_ctx:!y_pos!_to_f,c_crop,x_$xpos_mul_w,y_$ypos_mul_h", t.generate()); } + @Test + public void testFormatInTransformation() { + String t = new EagerTransformation().width(100).format("jpeg").generate(); + assertEquals("w_100/jpeg", t); + + t = new EagerTransformation().width(100).format("").generate(); + assertEquals("w_100/", t); + } + @Parameters({ "angle", "aspect_ratio", "dpr", From 97f92bab7eb3ec9c5d2822104d4e039919208c2d Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Mon, 4 Apr 2022 13:02:20 +0300 Subject: [PATCH 073/150] Add folder decoupling support --- .../src/main/java/com/cloudinary/Util.java | 5 ++++- .../com/cloudinary/test/AbstractUploaderTest.java | 15 +++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/cloudinary-core/src/main/java/com/cloudinary/Util.java b/cloudinary-core/src/main/java/com/cloudinary/Util.java index 2333e1cf..870616a6 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Util.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Util.java @@ -11,7 +11,7 @@ public class Util { static final String[] BOOLEAN_UPLOAD_OPTIONS = new String[]{"backup", "exif", "faces", "colors", "image_metadata", "use_filename", "unique_filename", "eager_async", "invalidate", "discard_original_filename", "overwrite", "phash", "return_delete_token", "async", "quality_analysis", "cinemagraph_analysis", - "accessibility_analysis"}; + "accessibility_analysis", "use_filename_as_display_name"}; @SuppressWarnings({"rawtypes", "unchecked"}) public static final Map buildUploadParams(Map options) { @@ -36,6 +36,9 @@ public static final Map buildUploadParams(Map options) { params.put("moderation", options.get("moderation")); params.put("access_mode", (String) options.get("access_mode")); params.put("filename_override", (String) options.get("filename_override")); + params.put("public_id_prefix", (String) options.get("public_id_prefix")); + params.put("asset_folder", (String) options.get("asset_folder")); + params.put("display_name", (String) options.get("display_name")); Object responsive_breakpoints = options.get("responsive_breakpoints"); if (responsive_breakpoints != null) { diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java index 79046890..42303df1 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java @@ -794,4 +794,19 @@ private void addToDeleteList(String type, String id) { ids.add(id); } + + @Test + public void testUploadFolderDecoupling() { + //TODO: Need to build a unit testing infrastructure + Map options = asMap( + "use_filename_as_display_name", true, + "public_id_prefix", "test_id_prefix", + "asset_folder", "asset_folder_test", + "display_name", "display_name_test"); + Map uploadParams = Util.buildUploadParams(options); + Assert.assertEquals("test_id_prefix", uploadParams.get("public_id_prefix")); + Assert.assertEquals(true, uploadParams.get("use_filename_as_display_name")); + Assert.assertEquals("asset_folder_test", uploadParams.get("asset_folder")); + Assert.assertEquals("display_name_test", uploadParams.get("display_name")); + } } From 6e226de33915d8ea8bf24f73d66fbb56a46e53cf Mon Sep 17 00:00:00 2001 From: adimiz1 Date: Tue, 5 Apr 2022 08:15:58 +0300 Subject: [PATCH 074/150] Version 1.32.0 --- CHANGELOG.md | 18 ++++++++++++++++++ README.md | 4 ++-- .../main/java/com/cloudinary/Cloudinary.java | 2 +- gradle.properties | 2 +- 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 01a6586a..b2acd3e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,22 @@ +1.32.0 / 2022-04-05 +=================== + +New functionality +----------------- + * Add folder decoupling support + * Support multiple acls in cookies + * Support structured metadata in `resources` api call + * Rename API call returns `metadata` and `context` + * Support start offset and end offset as expression + * Get the details of a single resource by asset_id + * Search by asset id + * Support metadata fields reordering +Other changes +------------- + * Fix `verifySignature` timestamp units + * Fix transformations API call + 1.31.0 / 2022-03-21 ==================== diff --git a/README.md b/README.md index 1b4cc58e..c6858e76 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ For the complete documentation, see the [Java SDK Guide](https://cloudinary.com/ ## Version Support | SDK Version | Java 6+ | |----------------|---------| -| 1.1.0 - 1.31.0 | V | +| 1.1.0 - 1.32.0 | V | ## Installation The cloudinary_java library is available in [Maven Central](https://mvnrepository.com/artifact/com.cloudinary/cloudinary-core). To use it, add the following dependency to your pom.xml : @@ -36,7 +36,7 @@ The cloudinary_java library is available in [Maven Central](https://mvnrepositor com.cloudinary cloudinary-http44 - 1.31.0 + 1.32.0 ``` diff --git a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java index 460beda5..dae66f00 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java @@ -38,7 +38,7 @@ public class Cloudinary { public final static String AKAMAI_SHARED_CDN = "res.cloudinary.com"; public final static String SHARED_CDN = AKAMAI_SHARED_CDN; - public final static String VERSION = "1.31.0"; + public final static String VERSION = "1.32.0"; static String USER_AGENT_PREFIX = "CloudinaryJava"; public final static String USER_AGENT_JAVA_VERSION = "(Java " + System.getProperty("java.version") + ")"; diff --git a/gradle.properties b/gradle.properties index d601b863..1354ca9a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,7 +13,7 @@ developerEmail=info@cloudinary.com # These two properties must use these exact names to be compatible with 'gradle install' plugin. group=com.cloudinary -version=1.31.0 +version=1.32.0 gnsp.disableApplyOnlyOnRootProjectEnforcement=true From 837b43b3f656ad37587744469a5a59bd201fd7d8 Mon Sep 17 00:00:00 2001 From: francistagbo <61406266+francistagbo@users.noreply.github.com> Date: Sun, 10 Apr 2022 08:29:19 +0300 Subject: [PATCH 075/150] Update Spring framework version --- samples/photo_album/pom.xml | 2 +- samples/photo_album_gae/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/photo_album/pom.xml b/samples/photo_album/pom.xml index b6210d57..9606673a 100644 --- a/samples/photo_album/pom.xml +++ b/samples/photo_album/pom.xml @@ -8,7 +8,7 @@ photo_album - 5.3.0 + 5.3.18 diff --git a/samples/photo_album_gae/pom.xml b/samples/photo_album_gae/pom.xml index f95b9dc3..b320750c 100644 --- a/samples/photo_album_gae/pom.xml +++ b/samples/photo_album_gae/pom.xml @@ -8,7 +8,7 @@ photo_album_gae - 5.3.0 + 5.3.18 1 1.9.37 UTF-8 From 82cd4cd64c461ceae9a989f2331c1343fe93f70e Mon Sep 17 00:00:00 2001 From: Yomes <1785648+YomesInc@users.noreply.github.com> Date: Sun, 10 Apr 2022 08:32:20 +0300 Subject: [PATCH 076/150] Fix double underscore handling during normalization --- .../java/com/cloudinary/transformation/LayerTest.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/cloudinary-core/src/test/java/com/cloudinary/transformation/LayerTest.java b/cloudinary-core/src/test/java/com/cloudinary/transformation/LayerTest.java index dba71ee7..d801c4dc 100644 --- a/cloudinary-core/src/test/java/com/cloudinary/transformation/LayerTest.java +++ b/cloudinary-core/src/test/java/com/cloudinary/transformation/LayerTest.java @@ -58,6 +58,12 @@ public void testUnderlay() { assertEquals(DEFAULT_UPLOAD_PATH + "h_100,u_text:hello,w_100/test", result); } + @Test + public void testPublicIdWithDoubleUnderscoresInOverlay() { + Transformation transformation = new Transformation().width(300).height(200).crop("fill").overlay("my__lake"); + String result = cloudinary.url().transformation(transformation).generate("sample.jpg"); + assertEquals(DEFAULT_UPLOAD_PATH + "c_fill,h_200,l_my__lake,w_300/sample.jpg", result); + } @Test public void testLayerOptions() { @@ -133,4 +139,4 @@ public void testToString() throws Exception { public void testFormattedPublicId() throws Exception { } -} \ No newline at end of file +} From 06b4f7d8948bd52acdb42ffde5e1ba6822233935 Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Wed, 20 Apr 2022 13:42:51 +0300 Subject: [PATCH 077/150] Fix unstable tests --- .../com/cloudinary/test/AbstractApiTest.java | 17 +++++-- .../cloudinary/test/AbstractUploaderTest.java | 4 ++ .../com/cloudinary/test/rules/RetryRule.java | 47 +++++++++++++++++++ 3 files changed, 64 insertions(+), 4 deletions(-) create mode 100644 cloudinary-test-common/src/main/java/com/cloudinary/test/rules/RetryRule.java diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java index e7cc0f32..e83cf042 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java @@ -4,7 +4,7 @@ import com.cloudinary.api.ApiResponse; import com.cloudinary.api.exceptions.BadRequest; import com.cloudinary.api.exceptions.NotFound; -import com.cloudinary.metadata.StringMetadataField; +import com.cloudinary.test.rules.RetryRule; import com.cloudinary.transformation.TextLayer; import com.cloudinary.utils.ObjectUtils; import org.junit.*; @@ -53,6 +53,8 @@ abstract public class AbstractApiTest extends MockableTest { private static String assetId1; private static String assetId2; + private static final int SLEEP_TIMEOUT = 5000; + protected Api api; @@ -137,6 +139,9 @@ public static void tearDownClass() { @Rule public TestName currentTest = new TestName(); + @Rule + public RetryRule retryRule = new RetryRule(); + @Before public void setUp() { System.out.println("Running " + this.getClass().getName() + "." + currentTest.getMethodName()); @@ -909,8 +914,10 @@ public void testRestoreDifferentVersionsOfDeletedAsset() throws Exception { "tags", UPLOAD_TAGS )); assertEquals(firstUpload.get("public_id"), TEST_RESOURCE_PUBLIC_ID); + Thread.sleep(SLEEP_TIMEOUT); ApiResponse firstDelete = api.deleteResources(Collections.singletonList(TEST_RESOURCE_PUBLIC_ID), ObjectUtils.emptyMap()); assertTrue(firstDelete.containsKey("deleted")); + Thread.sleep(SLEEP_TIMEOUT); Map secondUpload = uploader.upload(SRC_TEST_IMAGE, ObjectUtils.asMap( @@ -920,13 +927,15 @@ public void testRestoreDifferentVersionsOfDeletedAsset() throws Exception { "tags", UPLOAD_TAGS )); assertEquals(secondUpload.get("public_id"), TEST_RESOURCE_PUBLIC_ID); + Thread.sleep(SLEEP_TIMEOUT); ApiResponse secondDelete = api.deleteResources(Collections.singletonList(TEST_RESOURCE_PUBLIC_ID), ObjectUtils.emptyMap()); assertTrue(secondDelete.containsKey("deleted")); - + Thread.sleep(SLEEP_TIMEOUT); assertNotEquals(firstUpload.get("bytes"), secondUpload.get("bytes")); ApiResponse getVersionsResp = api.resource(TEST_RESOURCE_PUBLIC_ID, ObjectUtils.asMap("versions", true)); List versions = (List) getVersionsResp.get("versions"); + Assert.assertTrue(versions.size() > 1); Object firstAssetVersion = versions.get(0).get("version_id"); Object secondAssetVersion = versions.get(1).get("version_id"); @@ -937,7 +946,7 @@ public void testRestoreDifferentVersionsOfDeletedAsset() throws Exception { ApiResponse secondVerRestore = api.restore(Collections.singletonList(TEST_RESOURCE_PUBLIC_ID), ObjectUtils.asMap("versions", Collections.singletonList(secondAssetVersion))); assertEquals(((Map) secondVerRestore.get(TEST_RESOURCE_PUBLIC_ID)).get("bytes"), secondUpload.get("bytes")); - + Thread.sleep(SLEEP_TIMEOUT); ApiResponse finalDeleteResp = api.deleteResources(Collections.singletonList(TEST_RESOURCE_PUBLIC_ID), ObjectUtils.emptyMap()); assertTrue(finalDeleteResp.containsKey("deleted")); } @@ -1157,7 +1166,7 @@ public void testQualityAnalysis() throws Exception { public void testDeleteFolder() throws Exception { String toDelete = "todelete_" + SUFFIX; Map uploadResult = cloudinary.uploader().upload(SRC_TEST_IMAGE, asMap("tags", UPLOAD_TAGS, "folder", toDelete)); - Thread.sleep(5000); + Thread.sleep(SLEEP_TIMEOUT); api.deleteResources(Collections.singletonList(uploadResult.get("public_id").toString()), emptyMap()); ApiResponse result = api.deleteFolder(toDelete, emptyMap()); assertTrue(((ArrayList) result.get("deleted")).contains(toDelete)); diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java index 42303df1..2194afaf 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java @@ -3,6 +3,7 @@ import com.cloudinary.*; import com.cloudinary.api.ApiResponse; import com.cloudinary.metadata.StringMetadataField; +import com.cloudinary.test.rules.RetryRule; import com.cloudinary.utils.ObjectUtils; import com.cloudinary.utils.Rectangle; import org.cloudinary.json.JSONArray; @@ -81,6 +82,9 @@ public static void tearDownClass() { @Rule public TestName currentTest = new TestName(); + @Rule + public RetryRule retryRule = new RetryRule(); + @Before public void setUp() { System.out.println("Running " + this.getClass().getName() + "." + currentTest.getMethodName()); diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/rules/RetryRule.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/rules/RetryRule.java new file mode 100644 index 00000000..4d407610 --- /dev/null +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/rules/RetryRule.java @@ -0,0 +1,47 @@ +package com.cloudinary.test.rules; + +import org.junit.rules.TestRule; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +import java.util.Objects; + +public class RetryRule implements TestRule { + private int retryCount; + private int delay; + + public RetryRule(int retryCount, int delay) { + this.retryCount = retryCount; + this.delay = delay; + } + + public RetryRule() { + this.retryCount = 3; + this.delay = 3; + } + + public Statement apply(Statement base, Description description) { + return statement(base, description); + } + + private Statement statement(final Statement base, final Description description) { + return new Statement() { + @Override + public void evaluate() throws Throwable { + Throwable caughtThrowable = null; + for (int i = 0; i < retryCount; i++) { + try { + base.evaluate(); + return; + } catch (Throwable t) { + caughtThrowable = t; + System.err.println(description.getDisplayName() + ": run " + (i + 1) + " failed."); + Thread.sleep(delay * 1000); + } + } + System.err.println(description.getDisplayName() + ": Giving up after " + retryCount + " failures."); + throw Objects.requireNonNull(caughtThrowable); + } + }; + } +} From 3b64470dddf7163c9f387e9105f9724a8bc2f302 Mon Sep 17 00:00:00 2001 From: Adi Date: Mon, 25 Apr 2022 13:03:44 +0300 Subject: [PATCH 078/150] Version 1.32.1 --- CHANGELOG.md | 13 +++++++++++++ README.md | 4 ++-- .../src/main/java/com/cloudinary/Cloudinary.java | 2 +- gradle.properties | 2 +- 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b2acd3e4..436b867e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,17 @@ +1.32.1 / 2022-04-25 +=================== + + * Fix double underscore handling during normalization + * Update Spring framework version + + / 2022-04-25 +============= + + * Fix unstable tests + * Fix double underscore handling during normalization + * Update Spring framework version + 1.32.0 / 2022-04-05 =================== diff --git a/README.md b/README.md index c6858e76..472fbaec 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ For the complete documentation, see the [Java SDK Guide](https://cloudinary.com/ ## Version Support | SDK Version | Java 6+ | |----------------|---------| -| 1.1.0 - 1.32.0 | V | +| 1.1.0 - 1.32.1 | V | ## Installation The cloudinary_java library is available in [Maven Central](https://mvnrepository.com/artifact/com.cloudinary/cloudinary-core). To use it, add the following dependency to your pom.xml : @@ -36,7 +36,7 @@ The cloudinary_java library is available in [Maven Central](https://mvnrepositor com.cloudinary cloudinary-http44 - 1.32.0 + 1.32.1 ``` diff --git a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java index dae66f00..61622ade 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java @@ -38,7 +38,7 @@ public class Cloudinary { public final static String AKAMAI_SHARED_CDN = "res.cloudinary.com"; public final static String SHARED_CDN = AKAMAI_SHARED_CDN; - public final static String VERSION = "1.32.0"; + public final static String VERSION = "1.32.1"; static String USER_AGENT_PREFIX = "CloudinaryJava"; public final static String USER_AGENT_JAVA_VERSION = "(Java " + System.getProperty("java.version") + ")"; diff --git a/gradle.properties b/gradle.properties index 1354ca9a..6e7d0085 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,7 +13,7 @@ developerEmail=info@cloudinary.com # These two properties must use these exact names to be compatible with 'gradle install' plugin. group=com.cloudinary -version=1.32.0 +version=1.32.1 gnsp.disableApplyOnlyOnRootProjectEnforcement=true From a36d11ea19f7d9ca8d05803cd9babae67a4c5f18 Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Tue, 3 May 2022 12:40:26 +0300 Subject: [PATCH 079/150] Fix nexus publishing script --- build.gradle | 17 +++++++++++++++++ cloudinary-core/build.gradle | 10 ---------- cloudinary-http42/build.gradle | 10 ---------- cloudinary-http43/build.gradle | 10 ---------- cloudinary-http44/build.gradle | 12 +----------- cloudinary-http45/build.gradle | 10 ---------- cloudinary-taglib/build.gradle | 10 ---------- cloudinary-test-common/build.gradle | 10 ---------- 8 files changed, 18 insertions(+), 71 deletions(-) diff --git a/build.gradle b/build.gradle index 7fff49dc..ebe374c8 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,9 @@ import groovy.json.JsonSlurper +plugins { + id 'io.github.gradle-nexus.publish-plugin' version '1.0.0' +} + allprojects { repositories { @@ -9,6 +13,19 @@ allprojects { project.ext.set("publishGroupId", group) } +nexusPublishing { + transitionCheckOptions { + maxRetries.set(150) + delayBetween.set(Duration.ofSeconds(5)) + } + repositories { + sonatype { + username = project.hasProperty("ossrhUsername") ? project.ext["ossrhUsername"] : "" + password = project.hasProperty("ossrhPassword") ? project.ext["ossrhPassword"] : "" + } + } +} + tasks.create('createTestSubAccount') { doFirst { println("Task createTestSubAccount called with module $moduleName") diff --git a/cloudinary-core/build.gradle b/cloudinary-core/build.gradle index fa305516..37246e23 100644 --- a/cloudinary-core/build.gradle +++ b/cloudinary-core/build.gradle @@ -3,7 +3,6 @@ plugins { id 'signing' id 'maven-publish' id 'io.codearte.nexus-staging' version '0.21.1' - id "de.marcphilipp.nexus-publish" version "0.4.0" } task ciTest( type: Test ) @@ -87,15 +86,6 @@ if (hasProperty("ossrhPassword")) { } } - nexusPublishing { - repositories { - sonatype { - username = project.hasProperty("ossrhUsername") ? project.ext["ossrhUsername"] : "" - password = project.hasProperty("ossrhPassword") ? project.ext["ossrhPassword"] : "" - } - } - } - model { tasks.generatePomFileForMavenJavaPublication { destination = file("$buildDir/generated-pom.xml") diff --git a/cloudinary-http42/build.gradle b/cloudinary-http42/build.gradle index cb8ec796..7c94214b 100644 --- a/cloudinary-http42/build.gradle +++ b/cloudinary-http42/build.gradle @@ -3,7 +3,6 @@ plugins { id 'signing' id 'maven-publish' id 'io.codearte.nexus-staging' version '0.21.1' - id "de.marcphilipp.nexus-publish" version "0.4.0" } apply from: "../java_shared.gradle" @@ -100,15 +99,6 @@ if (hasProperty("ossrhPassword")) { } } - nexusPublishing { - repositories { - sonatype { - username = project.hasProperty("ossrhUsername") ? project.ext["ossrhUsername"] : "" - password = project.hasProperty("ossrhPassword") ? project.ext["ossrhPassword"] : "" - } - } - } - model { tasks.generatePomFileForMavenJavaPublication { destination = file("$buildDir/generated-pom.xml") diff --git a/cloudinary-http43/build.gradle b/cloudinary-http43/build.gradle index 23942327..47fe4701 100644 --- a/cloudinary-http43/build.gradle +++ b/cloudinary-http43/build.gradle @@ -3,7 +3,6 @@ plugins { id 'signing' id 'maven-publish' id 'io.codearte.nexus-staging' version '0.21.1' - id "de.marcphilipp.nexus-publish" version "0.4.0" } apply from: "../java_shared.gradle" @@ -99,15 +98,6 @@ if (hasProperty("ossrhPassword")) { } } - nexusPublishing { - repositories { - sonatype { - username = project.hasProperty("ossrhUsername") ? project.ext["ossrhUsername"] : "" - password = project.hasProperty("ossrhPassword") ? project.ext["ossrhPassword"] : "" - } - } - } - model { tasks.generatePomFileForMavenJavaPublication { destination = file("$buildDir/generated-pom.xml") diff --git a/cloudinary-http44/build.gradle b/cloudinary-http44/build.gradle index 7d533e05..a4c51ed8 100644 --- a/cloudinary-http44/build.gradle +++ b/cloudinary-http44/build.gradle @@ -3,7 +3,6 @@ plugins { id 'signing' id 'maven-publish' id 'io.codearte.nexus-staging' version '0.21.1' - id "de.marcphilipp.nexus-publish" version "0.4.0" } apply from: "../java_shared.gradle" @@ -98,16 +97,7 @@ if (hasProperty("ossrhPassword")) { } } } - - nexusPublishing { - repositories { - sonatype { - username = project.hasProperty("ossrhUsername") ? project.ext["ossrhUsername"] : "" - password = project.hasProperty("ossrhPassword") ? project.ext["ossrhPassword"] : "" - } - } - } - + model { tasks.generatePomFileForMavenJavaPublication { destination = file("$buildDir/generated-pom.xml") diff --git a/cloudinary-http45/build.gradle b/cloudinary-http45/build.gradle index 2d88dc60..f4b7613d 100644 --- a/cloudinary-http45/build.gradle +++ b/cloudinary-http45/build.gradle @@ -3,7 +3,6 @@ plugins { id 'signing' id 'maven-publish' id 'io.codearte.nexus-staging' version '0.21.1' - id "de.marcphilipp.nexus-publish" version "0.4.0" } apply from: "../java_shared.gradle" @@ -99,15 +98,6 @@ if (hasProperty("ossrhPassword")) { } } - nexusPublishing { - repositories { - sonatype { - username = project.hasProperty("ossrhUsername") ? project.ext["ossrhUsername"] : "" - password = project.hasProperty("ossrhPassword") ? project.ext["ossrhPassword"] : "" - } - } - } - model { tasks.generatePomFileForMavenJavaPublication { destination = file("$buildDir/generated-pom.xml") diff --git a/cloudinary-taglib/build.gradle b/cloudinary-taglib/build.gradle index 9d2313be..6db5af30 100644 --- a/cloudinary-taglib/build.gradle +++ b/cloudinary-taglib/build.gradle @@ -3,7 +3,6 @@ plugins { id 'signing' id 'maven-publish' id 'io.codearte.nexus-staging' version '0.21.1' - id "de.marcphilipp.nexus-publish" version "0.4.0" } apply from: "../java_shared.gradle" @@ -94,15 +93,6 @@ if (hasProperty("ossrhPassword")) { } } - nexusPublishing { - repositories { - sonatype { - username = project.hasProperty("ossrhUsername") ? project.ext["ossrhUsername"] : "" - password = project.hasProperty("ossrhPassword") ? project.ext["ossrhPassword"] : "" - } - } - } - model { tasks.generatePomFileForMavenJavaPublication { destination = file("$buildDir/generated-pom.xml") diff --git a/cloudinary-test-common/build.gradle b/cloudinary-test-common/build.gradle index c374de6d..31a8bae2 100644 --- a/cloudinary-test-common/build.gradle +++ b/cloudinary-test-common/build.gradle @@ -3,7 +3,6 @@ plugins { id 'signing' id 'maven-publish' id 'io.codearte.nexus-staging' version '0.21.1' - id "de.marcphilipp.nexus-publish" version "0.4.0" } apply from: "../java_shared.gradle" @@ -88,15 +87,6 @@ if (hasProperty("ossrhPassword")) { } } - nexusPublishing { - repositories { - sonatype { - username = project.hasProperty("ossrhUsername") ? project.ext["ossrhUsername"] : "" - password = project.hasProperty("ossrhPassword") ? project.ext["ossrhPassword"] : "" - } - } - } - model { tasks.generatePomFileForMavenJavaPublication { destination = file("$buildDir/generated-pom.xml") From 060b5e4e893f63526566ee51f6043309efb7ab21 Mon Sep 17 00:00:00 2001 From: adimiz1 Date: Tue, 10 May 2022 12:59:07 +0300 Subject: [PATCH 080/150] Version 1.32.2 --- CHANGELOG.md | 10 ++++------ README.md | 4 ++-- .../src/main/java/com/cloudinary/Cloudinary.java | 2 +- gradle.properties | 2 +- 4 files changed, 8 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 436b867e..fa46856c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,14 +1,12 @@ -1.32.1 / 2022-04-25 +1.32.2 / 2022-05-10 =================== - * Fix double underscore handling during normalization - * Update Spring framework version + * Fix nexus publishing script - / 2022-04-25 -============= +1.32.1 / 2022-04-25 +=================== - * Fix unstable tests * Fix double underscore handling during normalization * Update Spring framework version diff --git a/README.md b/README.md index 472fbaec..782d11df 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ For the complete documentation, see the [Java SDK Guide](https://cloudinary.com/ ## Version Support | SDK Version | Java 6+ | |----------------|---------| -| 1.1.0 - 1.32.1 | V | +| 1.1.0 - 1.32.2 | V | ## Installation The cloudinary_java library is available in [Maven Central](https://mvnrepository.com/artifact/com.cloudinary/cloudinary-core). To use it, add the following dependency to your pom.xml : @@ -36,7 +36,7 @@ The cloudinary_java library is available in [Maven Central](https://mvnrepositor com.cloudinary cloudinary-http44 - 1.32.1 + 1.32.2 ``` diff --git a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java index 61622ade..a695de14 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java @@ -38,7 +38,7 @@ public class Cloudinary { public final static String AKAMAI_SHARED_CDN = "res.cloudinary.com"; public final static String SHARED_CDN = AKAMAI_SHARED_CDN; - public final static String VERSION = "1.32.1"; + public final static String VERSION = "1.32.2"; static String USER_AGENT_PREFIX = "CloudinaryJava"; public final static String USER_AGENT_JAVA_VERSION = "(Java " + System.getProperty("java.version") + ")"; diff --git a/gradle.properties b/gradle.properties index 6e7d0085..9ee2713f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,7 +13,7 @@ developerEmail=info@cloudinary.com # These two properties must use these exact names to be compatible with 'gradle install' plugin. group=com.cloudinary -version=1.32.1 +version=1.32.2 gnsp.disableApplyOnlyOnRootProjectEnforcement=true From 3155774709a3a77ade76ecfaaedb9dbb09c1928b Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Thu, 9 Jun 2022 09:38:19 +0300 Subject: [PATCH 081/150] Bump spring frameworks version --- samples/photo_album/pom.xml | 2 +- samples/photo_album_gae/pom.xml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/samples/photo_album/pom.xml b/samples/photo_album/pom.xml index 9606673a..889de220 100644 --- a/samples/photo_album/pom.xml +++ b/samples/photo_album/pom.xml @@ -84,7 +84,7 @@ org.springframework.data spring-data-jpa - 1.3.0.RELEASE + 1.11.20.RELEASE diff --git a/samples/photo_album_gae/pom.xml b/samples/photo_album_gae/pom.xml index b320750c..d730e1f5 100644 --- a/samples/photo_album_gae/pom.xml +++ b/samples/photo_album_gae/pom.xml @@ -8,7 +8,7 @@ photo_album_gae - 5.3.18 + 5.3.19 1 1.9.37 UTF-8 @@ -99,7 +99,7 @@ org.springframework.data spring-data-jpa - 1.2.0.RELEASE + 1.11.20.RELEASE From ccaae9ebf676684c4f1566a83bdbf68266548c8d Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Sun, 4 Sep 2022 09:46:56 +0300 Subject: [PATCH 082/150] Add parameter `use_asset_folder_as_public_id_prefix` --- cloudinary-core/src/main/java/com/cloudinary/Util.java | 2 +- .../src/main/java/com/cloudinary/test/AbstractApiTest.java | 3 ++- .../main/java/com/cloudinary/test/AbstractUploaderTest.java | 5 ++++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/cloudinary-core/src/main/java/com/cloudinary/Util.java b/cloudinary-core/src/main/java/com/cloudinary/Util.java index 870616a6..2259adc7 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Util.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Util.java @@ -11,7 +11,7 @@ public class Util { static final String[] BOOLEAN_UPLOAD_OPTIONS = new String[]{"backup", "exif", "faces", "colors", "image_metadata", "use_filename", "unique_filename", "eager_async", "invalidate", "discard_original_filename", "overwrite", "phash", "return_delete_token", "async", "quality_analysis", "cinemagraph_analysis", - "accessibility_analysis", "use_filename_as_display_name"}; + "accessibility_analysis", "use_filename_as_display_name", "use_asset_folder_as_public_id_prefix"}; @SuppressWarnings({"rawtypes", "unchecked"}) public static final Map buildUploadParams(Map options) { diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java index e83cf042..ad77e202 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java @@ -769,7 +769,7 @@ public void testGetUploadPreset() throws Exception { String[] tags = {"a", "b", "c"}; Map context = ObjectUtils.asMap("a", "b", "c", "d"); Map result = api.createUploadPreset(ObjectUtils.asMap("unsigned", true, "folder", "folder", "transformation", EXPLICIT_TRANSFORMATION, "tags", tags, "context", - context, "live", true)); + context, "live", true, "use_asset_folder_as_public_id_prefix", true)); String name = result.get("name").toString(); Map preset = api.uploadPreset(name, ObjectUtils.emptyMap()); assertEquals(preset.get("name"), name); @@ -777,6 +777,7 @@ public void testGetUploadPreset() throws Exception { Map settings = (Map) preset.get("settings"); assertEquals(settings.get("folder"), "folder"); assertEquals(settings.get("live"), Boolean.TRUE); + assertEquals(settings.get("use_asset_folder_as_public_id_prefix"), true); Map outTransformation = (Map) ((java.util.ArrayList) settings.get("transformation")).get(0); assertEquals(outTransformation.get("width"), 100); assertEquals(outTransformation.get("crop"), "scale"); diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java index 2194afaf..14084d10 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java @@ -806,11 +806,14 @@ public void testUploadFolderDecoupling() { "use_filename_as_display_name", true, "public_id_prefix", "test_id_prefix", "asset_folder", "asset_folder_test", - "display_name", "display_name_test"); + "display_name", "display_name_test", + "use_asset_folder_as_public_id_prefix", true); + Map uploadParams = Util.buildUploadParams(options); Assert.assertEquals("test_id_prefix", uploadParams.get("public_id_prefix")); Assert.assertEquals(true, uploadParams.get("use_filename_as_display_name")); Assert.assertEquals("asset_folder_test", uploadParams.get("asset_folder")); Assert.assertEquals("display_name_test", uploadParams.get("display_name")); + Assert.assertEquals(true, uploadParams.get("use_asset_folder_as_public_id_prefix")); } } From 0d996e26f4204593691ba219148cb08d90ff5f99 Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Mon, 5 Sep 2022 07:51:15 +0300 Subject: [PATCH 083/150] Add asset_folder, unique_display_name to update resource API call --- .../src/main/java/com/cloudinary/Util.java | 8 +++++++- .../java/com/cloudinary/test/AbstractApiTest.java | 12 ++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/cloudinary-core/src/main/java/com/cloudinary/Util.java b/cloudinary-core/src/main/java/com/cloudinary/Util.java index 2259adc7..41a95a18 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Util.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Util.java @@ -11,7 +11,7 @@ public class Util { static final String[] BOOLEAN_UPLOAD_OPTIONS = new String[]{"backup", "exif", "faces", "colors", "image_metadata", "use_filename", "unique_filename", "eager_async", "invalidate", "discard_original_filename", "overwrite", "phash", "return_delete_token", "async", "quality_analysis", "cinemagraph_analysis", - "accessibility_analysis", "use_filename_as_display_name", "use_asset_folder_as_public_id_prefix"}; + "accessibility_analysis", "use_filename_as_display_name", "use_asset_folder_as_public_id_prefix", "unique_display_name"}; @SuppressWarnings({"rawtypes", "unchecked"}) public static final Map buildUploadParams(Map options) { @@ -160,6 +160,12 @@ public static final void processWriteParameters(Map options, Map if (options.get("access_control") != null) { params.put("access_control", encodeAccessControl(options.get("access_control"))); } + if (options.get("asset_folder") != null) { + params.put("asset_folder", options.get("asset_folder")); + } + if (options.get("unique_display_name") != null) { + params.put("unique_display_name", options.get("unique_display_name")); + } putObject("ocr", options, params); putObject("raw_convert", options, params); putObject("categorization", options, params); diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java index ad77e202..548a5865 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java @@ -1188,4 +1188,16 @@ public void testAccessibilityAnalysisResource() throws Exception { ApiResponse res = api.resource(API_TEST, Collections.singletonMap("accessibility_analysis", true)); assertNotNull(res.get("accessibility_analysis")); } + + @Test + public void testFolderDecoupling() { + //TODO: Need to build a unit testing infrastructure + Map params = new HashMap(); + Map options = asMap( + "asset_folder", "new_asset_folder", + "unique_display_name", true); + Util.processWriteParameters(options, params); + assertEquals("new_asset_folder", params.get("asset_folder")); + assertEquals(true, params.get("unique_display_name")); + } } From 38ff6dbcbbc3ba01feb57cb1edb7090499c2c172 Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Thu, 8 Sep 2022 07:07:14 +0300 Subject: [PATCH 084/150] Add function to get resources by asset folder --- .../src/main/java/com/cloudinary/Api.java | 8 ++++++++ .../java/com/cloudinary/test/AbstractApiTest.java | 12 ++++++++++++ .../main/java/com/cloudinary/test/MockableTest.java | 10 ++++++++++ .../java/com/cloudinary/test/helpers/Feature.java | 6 ++++++ 4 files changed, 36 insertions(+) create mode 100644 cloudinary-test-common/src/main/java/com/cloudinary/test/helpers/Feature.java diff --git a/cloudinary-core/src/main/java/com/cloudinary/Api.java b/cloudinary-core/src/main/java/com/cloudinary/Api.java index ee1123d5..4b0308ab 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Api.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Api.java @@ -129,6 +129,14 @@ public ApiResponse resourcesByAssetIDs(Iterable assetIds, Map options) t return response; } + public ApiResponse resourcesByAssetFolder(String assetFolder, Map options) throws Exception { + if (options == null) options = ObjectUtils.emptyMap(); + Map params = ObjectUtils.only(options, "next_cursor", "direction", "max_results", "tags", "context", "moderations"); + params.put("asset_folder", assetFolder); + ApiResponse response = callApi(HttpMethod.GET, Arrays.asList("resources/by_asset_folder"), params, options); + return response; + } + public ApiResponse resourcesByIds(Iterable publicIds, Map options) throws Exception { if (options == null) options = ObjectUtils.emptyMap(); String resourceType = ObjectUtils.asString(options.get("resource_type"), "image"); diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java index 548a5865..45c4a0b3 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java @@ -4,6 +4,7 @@ import com.cloudinary.api.ApiResponse; import com.cloudinary.api.exceptions.BadRequest; import com.cloudinary.api.exceptions.NotFound; +import com.cloudinary.test.helpers.Feature; import com.cloudinary.test.rules.RetryRule; import com.cloudinary.transformation.TextLayer; import com.cloudinary.utils.ObjectUtils; @@ -52,6 +53,7 @@ abstract public class AbstractApiTest extends MockableTest { private static final String CUSTOM_USER_AGENT_VERSION = "9.9.9"; private static String assetId1; private static String assetId2; + private static String assetId3; private static final int SLEEP_TIMEOUT = 5000; @@ -77,6 +79,8 @@ public static void setUpClass() throws IOException { assetId2 = cloudinary.uploader().upload(SRC_TEST_IMAGE, options).get("asset_id").toString(); options.remove("public_id"); + assetId3 = cloudinary.uploader().upload(SRC_TEST_IMAGE, ObjectUtils.asMap("asset_folder", "test_asset_folder")).get("public_id").toString(); + options.put("eager", Collections.singletonList(UPDATE_TRANSFORMATION)); cloudinary.uploader().upload(SRC_TEST_IMAGE, options); @@ -292,6 +296,14 @@ public void testResourceByAssetId() throws Exception { assertEquals(API_TEST, result.get("public_id").toString()); } + @Test + public void testResourceByAssetFolder() throws Exception { + if (MockableTest.shouldTestFeature(Feature.DYNAMIC_FOLDERS)) { + Map result = api.resourcesByAssetFolder("test_asset_folder", ObjectUtils.asMap("tags", true, "context", true)); + assertNotNull(findByAttr((List) result.get("resources"), "public_id", assetId3)); + } + } + @Test public void testResourcesByPublicIds() throws Exception { // should allow listing resources by public ids diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/MockableTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/MockableTest.java index c68a4131..7a9ef662 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/MockableTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/MockableTest.java @@ -1,6 +1,7 @@ package com.cloudinary.test; import com.cloudinary.Cloudinary; +import com.cloudinary.test.helpers.Feature; import com.cloudinary.utils.ObjectUtils; import com.cloudinary.utils.StringUtils; @@ -58,4 +59,13 @@ private static List getEnabledAddons() { return Arrays.asList(envAddons.split(",")); } + + protected static boolean shouldTestFeature(String feature) { + String sdkFeatures = System.getenv() + .getOrDefault("CLD_TEST_FEATURES", "") + .toLowerCase() + .replaceAll("\\s", ""); + List sdkFeaturesList = Arrays.asList(sdkFeatures.split(",")); + return sdkFeatures.contains(feature.toLowerCase()) || (sdkFeaturesList.size() == 1 && sdkFeaturesList.get(0).equalsIgnoreCase(Feature.ALL)); + } } diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/helpers/Feature.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/helpers/Feature.java new file mode 100644 index 00000000..875f9b9f --- /dev/null +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/helpers/Feature.java @@ -0,0 +1,6 @@ +package com.cloudinary.test.helpers; + +public class Feature { + public static final String ALL = "all"; + public static final String DYNAMIC_FOLDERS = "dynamic_folders"; +} From b9b139f13d62d3ca955f35f4b8fc4ec655c5df3e Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Thu, 8 Sep 2022 08:28:05 +0300 Subject: [PATCH 085/150] Fix `videotag` missing `authtoken` --- .../src/main/java/com/cloudinary/Url.java | 1 + .../java/com/cloudinary/test/CloudinaryTest.java | 13 +++++++++++++ .../test/java/com/cloudinary/test/UploaderTest.java | 3 +-- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/cloudinary-core/src/main/java/com/cloudinary/Url.java b/cloudinary-core/src/main/java/com/cloudinary/Url.java index b9fb0407..360193c0 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Url.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Url.java @@ -77,6 +77,7 @@ public Url clone() { cloned.urlSuffix = this.urlSuffix; cloned.useRootPath = this.useRootPath; cloned.longUrlSignature = this.longUrlSignature; + cloned.authToken = this.authToken; return cloned; } diff --git a/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java b/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java index 763cb286..c46672d4 100644 --- a/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java +++ b/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java @@ -1196,7 +1196,20 @@ public void testVideoTagWithPoster() { .poster(false) .videoTag("movie", emptyMap()); assertEquals(expectedTag, actualTag); + } + @Test + public void videoTagWithAuthTokenTest() { + String actualTag = cloudinary.url().transformation(new Transformation()) + .type("upload") + .authToken(new AuthToken("123456").duration(300)) + .signed(true) + .secure(true) + .videoTag("sample", Cloudinary.asMap( + "controls", true, + "loop", true) + ); + assert(actualTag.contains("cld_token")); } @Test diff --git a/cloudinary-http44/src/test/java/com/cloudinary/test/UploaderTest.java b/cloudinary-http44/src/test/java/com/cloudinary/test/UploaderTest.java index efbf9190..4734707c 100644 --- a/cloudinary-http44/src/test/java/com/cloudinary/test/UploaderTest.java +++ b/cloudinary-http44/src/test/java/com/cloudinary/test/UploaderTest.java @@ -30,5 +30,4 @@ public void testTimeoutParameter() throws Exception { "timeout", 1); ApiResponse result = cloudinary.api().resources(options); } - -} \ No newline at end of file +} From 6d2f9c9046410faa3dd6e0d3198bc479850e8c0f Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Thu, 8 Sep 2022 08:45:26 +0300 Subject: [PATCH 086/150] Fix upload with unicode characters --- .../com/cloudinary/http42/UploaderStrategy.java | 3 ++- .../com/cloudinary/http43/UploaderStrategy.java | 2 ++ .../com/cloudinary/http44/UploaderStrategy.java | 2 ++ .../com/cloudinary/http45/UploaderStrategy.java | 2 ++ .../cloudinary/test/AbstractUploaderTest.java | 6 ++++++ .../java/com/cloudinary/test/MockableTest.java | 1 + .../resources/\327\220\327\221\327\222.docx" | Bin 0 -> 12298 bytes 7 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 "cloudinary-test-common/src/main/resources/\327\220\327\221\327\222.docx" diff --git a/cloudinary-http42/src/main/java/com/cloudinary/http42/UploaderStrategy.java b/cloudinary-http42/src/main/java/com/cloudinary/http42/UploaderStrategy.java index 9984f015..0e38365d 100644 --- a/cloudinary-http42/src/main/java/com/cloudinary/http42/UploaderStrategy.java +++ b/cloudinary-http42/src/main/java/com/cloudinary/http42/UploaderStrategy.java @@ -23,6 +23,7 @@ import java.io.IOException; import java.io.InputStream; import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.util.Collection; import java.util.Map; @@ -71,7 +72,7 @@ public Map callApi(String action, Map params, Map options, Objec Charset utf8 = Charset.forName("UTF-8"); - MultipartEntity multipart = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE); + MultipartEntity multipart = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE, null, StandardCharsets.UTF_8); // Remove blank parameters for (Map.Entry param : params.entrySet()) { if (param.getValue() instanceof Collection) { diff --git a/cloudinary-http43/src/main/java/com/cloudinary/http43/UploaderStrategy.java b/cloudinary-http43/src/main/java/com/cloudinary/http43/UploaderStrategy.java index bb748f8f..88ce4b90 100644 --- a/cloudinary-http43/src/main/java/com/cloudinary/http43/UploaderStrategy.java +++ b/cloudinary-http43/src/main/java/com/cloudinary/http43/UploaderStrategy.java @@ -3,6 +3,7 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.nio.charset.StandardCharsets; import java.util.Collection; import java.util.Map; @@ -87,6 +88,7 @@ public Map callApi(String action, Map params, Map options, Objec MultipartEntityBuilder multipart = MultipartEntityBuilder.create(); multipart.setMode(HttpMultipartMode.BROWSER_COMPATIBLE); + multipart.setCharset(StandardCharsets.UTF_8); ContentType contentType = ContentType.MULTIPART_FORM_DATA.withCharset(MIME.UTF8_CHARSET); // Remove blank parameters for (Map.Entry param : params.entrySet()) { diff --git a/cloudinary-http44/src/main/java/com/cloudinary/http44/UploaderStrategy.java b/cloudinary-http44/src/main/java/com/cloudinary/http44/UploaderStrategy.java index e075db29..3afc8bce 100644 --- a/cloudinary-http44/src/main/java/com/cloudinary/http44/UploaderStrategy.java +++ b/cloudinary-http44/src/main/java/com/cloudinary/http44/UploaderStrategy.java @@ -4,6 +4,7 @@ import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Field; +import java.nio.charset.StandardCharsets; import java.util.Collection; import java.util.Map; @@ -88,6 +89,7 @@ public Map callApi(String action, Map params, Map options, Objec MultipartEntityBuilder multipart = MultipartEntityBuilder.create(); multipart.setMode(HttpMultipartMode.BROWSER_COMPATIBLE); + multipart.setCharset(StandardCharsets.UTF_8); ContentType contentType = ContentType.MULTIPART_FORM_DATA.withCharset(MIME.UTF8_CHARSET); // Remove blank parameters for (Map.Entry param : params.entrySet()) { diff --git a/cloudinary-http45/src/main/java/com/cloudinary/http45/UploaderStrategy.java b/cloudinary-http45/src/main/java/com/cloudinary/http45/UploaderStrategy.java index 175653cf..f4712515 100644 --- a/cloudinary-http45/src/main/java/com/cloudinary/http45/UploaderStrategy.java +++ b/cloudinary-http45/src/main/java/com/cloudinary/http45/UploaderStrategy.java @@ -22,6 +22,7 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.nio.charset.StandardCharsets; import java.util.Collection; import java.util.Map; @@ -84,6 +85,7 @@ public Map callApi(String action, Map params, Map options, Objec MultipartEntityBuilder multipart = MultipartEntityBuilder.create(); multipart.setMode(HttpMultipartMode.BROWSER_COMPATIBLE); + multipart.setCharset(StandardCharsets.UTF_8); ContentType contentType = ContentType.MULTIPART_FORM_DATA.withCharset(MIME.UTF8_CHARSET); // Remove blank parameters for (Map.Entry param : params.entrySet()) { diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java index 14084d10..89b502fb 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java @@ -799,6 +799,12 @@ private void addToDeleteList(String type, String id) { ids.add(id); } + @Test + public void testUploadLocalUnicodeFilename() throws Exception { + Map result = cloudinary.uploader().upload(HEBREW_PDF, asMap("resource_type", "raw")); + assertTrue(((String)result.get("public_id")).contains(".docx")); + } + @Test public void testUploadFolderDecoupling() { //TODO: Need to build a unit testing infrastructure diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/MockableTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/MockableTest.java index 7a9ef662..2308d3c2 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/MockableTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/MockableTest.java @@ -15,6 +15,7 @@ public class MockableTest { + public static final String HEBREW_PDF = "../cloudinary-test-common/src/main/resources/אבג.docx"; public static final String SRC_TEST_IMAGE = "../cloudinary-test-common/src/main/resources/old_logo.png"; public static final String SRC_TEST_VIDEO = "http://res.cloudinary.com/demo/video/upload/dog.mp4"; public static final String SRC_TEST_RAW = "../cloudinary-test-common/src/main/resources/docx.docx"; diff --git "a/cloudinary-test-common/src/main/resources/\327\220\327\221\327\222.docx" "b/cloudinary-test-common/src/main/resources/\327\220\327\221\327\222.docx" new file mode 100644 index 0000000000000000000000000000000000000000..2022c4ca16d5b6b48dc0c5035fdca48bf07bb174 GIT binary patch literal 12298 zcmeHN1zQ}+)*hTdaDo$pyK8WF53a%8-CY8M2X}V}?g4_kJ4|rb;32>_*}HppH+R2Z zaBn})bWiuG_f&QDv8rbUXW^!@dNEopD`enR3YLJtVzgOZ$YeT{XtX9Y1S{$8r;Z_u=$b#67(!MX_pqZ z>HUmxDKo7Y9V?3_houf zMu@oa)wH}yjoh`YXDYa&D2R4mv8@$C6zaHjJOIz0eDEt-fok!Kk#>xNywwjWc+I@x zR%-_gX{iIL&w`G2bTU#x$BdG(6;Zp$8~ zmx5>6Lm^C7+%g=I9UARs0Wz9)to}0In)b@fa;}iQFO4vG%>x*D2P?O9` z9~<)pRIA&oa+uJ}5@kt!O^0XA#7LeIXIO!NciujA=$YSH-1i}b?nUm44~!4qraI_a zPkRx&xB?t!#G3W`8+P~^x!v+Z_}JFx@SX0S7#qh;%Ub#mihdfFQiv%Sh3Y{i%cI6hwvgq* zu%=*qA%nz`-WQBV+b_~1OhI$zI1c{`au17t-%X~j8~J)lEEznNAx|s zxSM#oJp!G88Cq*(UPYg1#nnMH_SrC+Eh(1CpAO z7(5l!6~&D1Sk^xn@%&zSD&E^MM8U}|%OTFVAhjlah;3lB%h%oEU&TyPW)GTyb~a88 z-)t{MK4@Xv2U-q(V}?kwP>#{wF&$BPXq)D!Xf!~y#&|M4n=Xj>;gI)1>$pgm?X`{Y zVs>3LSqMgZ<{h1dYcIPtRyN*yLI_@AZGJk-&`tv!Fo4wiwV@d4i zOeuu^@FqB!qBWMfNIQ|_(VxtbTS=y80v+*JeOmLC`2DmQ`)}bV`#G zFf`JGm*pHU>ffJ|WQY{XO4;*F;0(+_lLTH(t_NG~AeY#2Q5`CSrd=%5y(&xb^7Xs5 z=RStq9;S(8V{E5vX>)xf4DNq=zrA1hDoaXPQ@8l+rNkqI29$dcqTl`jJW_wr%mv;| z?D#oJT$!119PBM39QepBQE-y3Av$7p}4 zg_JP2PSa)7r|ZS*8fSM#8=V1h7=65vwfWHM%NHTg&SbZ~GTzn7uY-e^JGK7Y&QyMO z^Co^(>LBHql0q@{}-E zv}F3)-r82urZYlw+gl#Og-&0U%MQHrY@6QBHi$PBYVEK?`meItOXSZ4j~V;+;9Rgi z4obaa)<$rLlOOgx;Rd0qN{^kXG@rMcrRiRiLaRaDX4yTcX59bqs@RQt36ho@5F)3` zk`QF^QQ;_-l}@s4!{A;yh@wKKR!5=MXEy^5W$tK&dkB_48wzV|z%KRfh?6p7% z-HWlSjm~OGsiVpFt>=zaDNYmq94iyu5pKX)ui~6RN7Q{_wbufTd+F=yQz29zbQxPlhd)|Xr zKL6=t8n4V!reOhqp*H})E3h#9CN<9HCN?IFznz(XI+|lmnMiyI)X#9=h(cRNJjeD8 zD%htbzgaDCfEt2gI+U%7Dzhx6)|MNXLf>aQzJSh%6?xgRgDU)zxpzCB$mo+)22tGM zYbjRx>)sgMpcid{ssf+Oo?6RVTiKj8HXl>CB~lQ-#7ArMsXGv602fop3PHY3ulM)G9)xk6+nqea(1efz)_!);5pbL`zhC(Z=yeaq4FVpI+%CN7u( zWyB~tTF6dzq(Qn+DH=^mhf;{Sq=Pv%7R?p;qqLh@p|{|MK1m23j?(996(bR0qk);S z@92nVil+p`%MJ#a%sl*Ew}nTFWMs0=s}WC5BRtr{R>U-j#!ikRk4+!75rD<)^aDLT z4LN)Fdiibh)etJSTd-q7Mw1#xGXOTcZuxf%MdPOQ=ShnMR5n`9x9N|bb6tB^3r**` z`aUn)VGHH#5CsTeQ<0o<>JRKT9`)K5IIpb~m#wWg(i3gJTH(1PMNmlyA(YOD4O9WuPMkhDDIDlN*`vU{20EX1$`|~8-0L3}3LUkX zRc8x$T|X}PJ^tv0JacqT2_uTdLEPi!ceSm-;V{<(5PiE%;0i|_l5tK@%z>uHMf7|_ z3gzPyKvlc$xmdqNh6e}r-P1ou7!!;#n*2h<8YK!Rod`PErl}I$AN!h z%a+*LSes|@{M&o}pk_*rM4@1$G*0Sff)K9mX(cD?h#IkD2I5fN+reYv9M*b{fp5EqT&0&7q?Qt`bFCOcp)`cH58TEpeYl8r4zPD%Q|4f3bMqD7dg zjgx)&wn%G;Kpc^gE~_QQbQxU2e+NMxa{5{1)5d92_Q^_Y=rKf|>F%m4858ToR-im; zBlX$0Maddn`HHEj^e}PrGeg-aW;~eK+4@|)QADojLXk?tsTsUkeQ1c#;(*q@?F) z8kQRsNpHz*SGwvY^RR-cS9-W3s=f(8*qTF8pkJIRbvy1#P~jFEGOqhf{l!L&9b(Jq z+W|Ja51WFmVY39?WL?^BMbZ7&1vat0`-=Ft<;LSQxNUnOIM2|2Z71R%bhwh3dshl!i=4L1EGt6Gg3QFy4x z#Y&N5Ki#9YW*IoX#m6BpQ9d{4B!?==**1)o~i~UFaynKi-E3 zy`@hU-39T(uH`vB+10pwh}g=Pyuw-R+DUzx>aLybH`kJ@x60zEwy4uaJH;x#J8SQ5 zo#U9tY!>KNtZ1u>w=9B08CGS{TbO|B-xdk@P4t^slku)TQa4(#X%qD<(0s7ohD}T1 z+rt^xS%YIIWjkudxEq2VbBFyNJggEPDm6ejRG2G3RyW!l>qC}@SyVjzI3Q|xs)#O9 zv9~6e0Mu@nSMmBGI@Ca$owakN4jOW2=_b`=igz(!P&LftBi3+PB#=Cl*fQFS9lxiC z4*iy{YSP7w=4dmU&G#N{lDHBh&cw8KoN2pyK2x=m-x5Dit;4?**hHm>d{B%LU8hZ)kjrC+MCq66n> zhuARor&L{A7&G5e65a~+op}n4p-3kt2~c^sR4ZHFuX&apJzO7lRjYmPSQcT50B)9L zSMdcCJvi5R+f@%Vfz}4fl^<5a`%H?C)@!lm&rZu5Hr;NKAx3!3XG2ds+ZL!Aj@Ar@ zj&8LIT_^VwzenXP5#2y_&b{V$⋘;X}#{UdZ|??&JHiFm!G%av|L!EUhdLi+Qfd| zijv$Inpyo>eRrc;27(IBUh4S(*D=jAzXJ-prGpC;puwHG&c7+SoNB{kE z_v9r_t41S6t~}bx1&3I>?kx39D!N4^JR_vkl0)R zwFkIySe`t#L_<6>GY6(Oc^^|EPT1}on_f-?1#n2d?=5&Uvo7d-{`BqkE9k^Y4hX@{ z2SCVm(vuGwPT`Ir(Nzm3^`WpL0jx^)#RVudL~$wK$`K~TFAPowvREQ3;SFr%~1V#gB}ICKY&jAYP+)Rt^a#AyIzeiisn6X&5W4UO%4|^-PEFpGdj% zXpX@%-VWmbp#N#DL*>r=BL2KWsM1)fJ``$m6i!m?jLS>d`N{|Oa~nN34U>Xl6L*yN z6?fp(i|%GJl>~;;J2kOsMZ%ePoL~&r^=(2tff%nA(pv_-Wa$UEH$R$Ci z!cJd_kFQG6;Z~}vP?y?5hdTMPnmN}IBM>MW4$fjm^3^0 z@KB9Bq_T;BLkVjQ)OlW(YW0kfAHm*bo%g-aly*{yV%*(wV6h-=Fpqh;b>-=OLGbOF zqfUuK&-wO*nMI#s$@m9>V`guHJE(6}Y}knhG9RWGp}Su7{hoYzz~u%*6rT*I`oBhQJ;5{&A~b{*a+RhZ!CRK%(xTqRN0lTQvm zA6do{6{?{pMhC6B&JE5ktD$S=w%Q`rE>g_+PuZBDTN$n+_V^_|P&HbF6(Y-MkNV_H z+hW$Yi80D_9E;lRoAl@J?C2M(YAGr)cqDUk<61OOj0Ncsg!`kFG%hH~y?X=R0Ht>~a z=B#V#-NX8z`r8YFJ>W@iL$PbLf-&a=>I=;hDdC;IWZ&WXz0yhJ-JIUrv{Gcxe z`~r65Iv=0Xdb?RC9EoRUra;AON?kLG;v_!2gnX;|r{1q&Ji4dD`&f30^EtC(e4oEB zbpE(;jK{WPo`8apyi6eDC8Uoq^k8|tw-HE5_e_?|t4cI(lJrTqWAydFi;=A19eJt* za@tM0!}0BO;bA)WC^1xvF-EZmO>Usu@u$S?5hgQ1S0y2!Sxx%&6gnAPGq zBt*H!jr-8z`Yx=1FoXFdS~*k?a-GpGbhL|sJBaCn4pH1%8zA&G2`P8*R~`nA8Hy>F z!AUoF`CoThK41IoDm+<&7TTD;m$jn~o#SWMu`oD3vb2pHCSTKDel3)ZC-&4o?S@e`h$ah~by zV_COj*Im_k#1!+OylW$$*JkZgB^-6DvU6T<2Gtz;S-B;j>8BzwYEq55F1D`^?|LQZ zB1MIa(>zG%r(p}otld}88F!#Tl|1Pi4CD+XKBzLJs8LJ#4DWHWcyCVCD-vZyk2cPx zqb#_k#->X16z4OVrXP+`EA%FYlVoY>%VLvkc4G1R40_c2K2OLba369CYZe`z1#Nx6 zg>iW82ZB z7;vx+Y>}E)p(JZK47wXmzo6#uKC=xB) zIFO1lBjb_sFJ;l@LqjPF83j8jVW8CG-led*XFvv=(}jj9FVU)f7XPINgGX1M5#VsC48q+U_^>3Ao*hI<*okSPG<@r&i%)QU>ffs*mlH6ll;v z+y({|VVrU-wLk1hzis#w5_fyx4rGL12bqTB&Yv%Ly$?->g=KALVM^Hu2`I!>#hzo! z%PO-FB~+UU|6Ylgt@8NWpCYttZ8?09-ECgDTtt&Pq1R)~nr^RhwhGQ_bg8>+sutj7 zw(X%&Q8(epqEUZRq##kE?ZEN_aBaK=2nzIycxxk;r?rqy?3jC_Rj_l8yq2SsYSl+t zyAUB^{OOflbD!-Tizee_mHA<+#amh}IV;HySsoJyO?vaNwy0M<5{t`#WRj5~>&a+x zoNj?DN3{{Dxcm7^0?;RRtL93O8Ts_?oMfO{KZ|#sRFAryOjc>_u?5qCa(|8Y1{$G* zmT@hfRpZWW6j=w|GapzR7-TE!1NH^xIFm`Co2=iuhn*TyDC4btJ|mOug;+z_Jbb#L zXik>VH9d^Zg~%Goi+zDx$B%y3r0;#>mIj+uO2Xwsy1c@g*CPV!N(@ht8bL-%60c<% zp%Ocq8+xno#F0Q3X>RU@TU`a9;X-p5jyGx8e{-HR9LY%Yj9L-;@=Tu&<9jn|V(F>W z`+0+&_Ke5$u%35oD7di%xZm^XMlU4lX4$8ln>R*+kyg*i1C`#%p?Lm4KR$-Fy&Jb( zFLAvgG4)``C|2z7P-$B^FS&Jdzfiw4rmOS7opE^&MRwE;D>)y+!jQmLylT`#x@ypq z57PfaY~&6dw*B&qC^dYrmx+mn{3TEt7Ak+bt4k6F$2TMz2H!XJ=c!U2hExkugQ?6x zocj?YbEoFL%GPLCNq=g9QWPsxKAsueS4jTsaxtbgOe5mb{)~`17#ZDd>LD;~+rA&D(y0lzpQ216q)LE>QN9k9Y8O>BuFkTj1jx{!>!u`$bD zc6+zMYURslCP7fTJ$79zqcOq7XpO?DhAN{%`3eh&^DA5ag24p-MKe|4fuT$N*M3>o zCUFj!2l2%lq{i#}f|l$;`r{;tJlV9+FX_}2aF0P_;UIYa)z|HMQr4ocuYtiU8P+j6 z)$yDpF<#cw z{v>UW75d#8LZvv{Z1v)CbSrwGc~GusQH&HyJ)(i_B#mdNhifa;Omv(Dlk{! zKPm||Co2)d*rZ&U?39RbIIsG*fCyVYKm=-j@es^^kL_QOpSLC| zsHZ0X9({P#g=Ti1v#x1pn84vdyJ6>ZX?d%Xz=?K?&8(20$_x!>`Ev*So-#j7CFkqc zDW3U6qN9eyW5kvN7B1;l3?BqD?|y9MJs=aM^PlI+Tz8=EW>EVR-9$kTs35n6wiCXH zXz!_tvy})`-7`?XX&~)pb6-q!j$%xYRGxK)4s4qSzG~ltKO3G`<2v4~BCvt^^7?dm zRPD|2dX={|%xf6#x1BNkhf4|xbJvCblk5caUux1P+39lC2 zkkSg2u#6S>A!>_J-xBbaU(z;oDy>0R%*L*hvv=LeASr>AMLuTFGBFz#hJqhI4K2x? z$K$>KQ5Z^PS4uprV9Awe@Eax8KhbkN__+5^jJ-oxA|CoDWf4df|q?q=GUyM+!{?}C4Q(CzAJ3a{JK_8RetkU6eLOwIrpgyP{DHW*kwotkFvB9 z7>8yvRkl?u3PnC&-wZ%m%jM5Q)!nkVW>yrUbY5KFS#Wq>mdD5 zrVO*8S2;=TQ_U_HsG5<4&^ydVE7!v7s6{B`?_78A9x1aMDSRkr&c>cA_G;Tzf<5EU zR#n(>>NlhC;eps1>sMiH8<4urc>3N7xu-bywydyiOpHOq%X6)9xBAD?^FIdeX9(2t z^56`KFF2oq`A6XHW@7m6FZ%)+Gx}EGQW3!UZTDx9p|+x7OlmcQmjinJ?^oc$59UJ2 zTjC?jPiM}SOP%fvZ{weDw-|^ocgB~tF(7fTT5yow#rZF2;B*f4J*-$VVZ0FAK{S~X zVYm@AY-#RD<#ETKGZ9`;S7tFAjY1{2%My3NeAftb2sIGvKD-)SS7EjUso~%MN^?1fJ zxf84+T4Y%=3qPpb+DKI;G4D_(*jGwUeihW2fxxZ0@Wx8fqQ z=yGK9!myhN^2j{nKJZoOgFli`>`84cR(kTDMAo1{r|AXKKP{Y63wcE$!KERAZ~y@M zAM#C?I#kvOb|)992{jHSiSQk}lWxzvmM4h0(Bgz!}g$24b=@zOBU@(9C#S z+q(Wkj~N?K;ynk<+osf?i5=m!!eL7mWv(i@$90?SCLN1p)HWhqp(5MRS2!OaMm*(VbuGB4a4llsa^DKh5+zl{aOvp5;gJ3%#;yi>oG~l)5H> zB>npHt7?=W7Cu@wDqhD;t9d8)?Tp)X&KXbuEhWF9=3yv`f^z`!mAokDQw2)y5iQYa z@@3~{Px&llyj`A*UWMsyDCt{nmcAM0NJ?YwVKnTP=V;O%AesJ7;{_)r`RITjH+2uB zn!rD1K;bOca~#2xYp~Ryfis}sw5Ot@oxKyIk)7jj0s}59`d``;tV+OmUAsUg%+Rys zV}V$Z2n1&xYL_vq-k9-_&W*!DgTzTep+)&%r#?hCTF0WU!o*Bi&q`5UK2ndbAr~TmkK1eaCXRWRB3Ots?OL;&vL4y$AGLrnlNT2 z6(^H5UDv0n(0oM0<7wT~G$^kMMgf-(Y{hH@?w9=E+LCaFuP|LXUo%aFd~}Yx$-Et! z@oo_GAn30ll7FPq6HD0Um;Q2Io@(#>M2A@n@ni=a=+~PJVe>7yXZ%Ok;%B_BZx0sK z0kEK={#8&7?CpOVw*Sc~c-p{6hVqC!I6dD^dV!*JTKTR(4aNqjNZT8bJPR-z0g+)v z+bqF0_)Ub?6NlsTpNx7+uv+z8e`Z~x3@yo|zwB!tWUZg3wn=C4E44K{;*FHjAP3fI z?7{)>*#!iG_SShr3z$vG42)8nsPAd}^Q>zy9OP|eGM7W-$pUi?s;U}#D-(zamwOo^ z4EyY}Cuvkz1rTw6hO;)#b(Bhxb{oVN zjR9nd1=Z|@LV|P@ z2%pIHD|TTr&q6Y}BKUl9{>+L%K+=PQoqsNx{?|A8^ZXAb)QU2HXYltD&p)96Kms_b z`b)v*ufShx-~NQwfr}OXqY~~{_}^<`{saR6n+U(d|DVd3Upf6+AMqzI9B|a~kJS>t zviLQ-^d}2Ka9sHti@)ZYeue+Kf&3@j1LqI;zqgZr1^*hv{t0Fw`yKpCNc$^?U&F9J zIn&f#xC*{}G&JLNyo0KhgS0Pr6!`d9ehP32$VQ8a&n|86)HWnjSK@w1#55zq}b KuB`Mw@BR;s?&gvJ literal 0 HcmV?d00001 From 92af7ccd65b51fe5650c10344083565b023cabe0 Mon Sep 17 00:00:00 2001 From: cloudinary-bot Date: Mon, 12 Sep 2022 06:35:50 +0000 Subject: [PATCH 087/150] Version 1.33.0 --- CHANGELOG.md | 8 ++++++++ README.md | 4 ++-- .../src/main/java/com/cloudinary/Cloudinary.java | 2 +- gradle.properties | 2 +- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fa46856c..7bb2294c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +1.33.0 / 2022-09-12 +================== + +* Add dynamic folders support +* Fix VideoTag not appending auth token +* Fix upload with Unicode character not appending a file extension +* Bump springboard version + 1.32.2 / 2022-05-10 =================== diff --git a/README.md b/README.md index 782d11df..48f45ecd 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ For the complete documentation, see the [Java SDK Guide](https://cloudinary.com/ ## Version Support | SDK Version | Java 6+ | |----------------|---------| -| 1.1.0 - 1.32.2 | V | +| 1.1.0 - 1.33.0 | V | ## Installation The cloudinary_java library is available in [Maven Central](https://mvnrepository.com/artifact/com.cloudinary/cloudinary-core). To use it, add the following dependency to your pom.xml : @@ -36,7 +36,7 @@ The cloudinary_java library is available in [Maven Central](https://mvnrepositor com.cloudinary cloudinary-http44 - 1.32.2 + 1.33.0 ``` diff --git a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java index a695de14..2229fc8f 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java @@ -38,7 +38,7 @@ public class Cloudinary { public final static String AKAMAI_SHARED_CDN = "res.cloudinary.com"; public final static String SHARED_CDN = AKAMAI_SHARED_CDN; - public final static String VERSION = "1.32.2"; + public final static String VERSION = "1.33.0"; static String USER_AGENT_PREFIX = "CloudinaryJava"; public final static String USER_AGENT_JAVA_VERSION = "(Java " + System.getProperty("java.version") + ")"; diff --git a/gradle.properties b/gradle.properties index 9ee2713f..2fac0474 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,7 +13,7 @@ developerEmail=info@cloudinary.com # These two properties must use these exact names to be compatible with 'gradle install' plugin. group=com.cloudinary -version=1.32.2 +version=1.33.0 gnsp.disableApplyOnlyOnRootProjectEnforcement=true From 4d5edd7c7304ede47a6345a79d085fa9994666c9 Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Fri, 27 Jan 2023 11:55:25 +0200 Subject: [PATCH 088/150] Fix create user tests --- .../java/com/cloudinary/test/AbstractAccountApiTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractAccountApiTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractAccountApiTest.java index 0fe3c95a..8dc30fc9 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractAccountApiTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractAccountApiTest.java @@ -422,19 +422,19 @@ private ApiResponse createUser(List subAccountsIds, Boolean enabled) thr } private ApiResponse createUser(List subAccountsIds, Account.Role role) throws Exception { - String email = String.format("%s@%s.com", randomLetters(), randomLetters()); + String email = "sdk+" + SDK_TEST_TAG + randomLetters() + "@cloudinary.com"; return createUser("TestName", email, role, subAccountsIds); } private ApiResponse createUser(List subAccountsIds, Account.Role role, Map options) throws Exception { - String email = String.format("%s@%s.com", randomLetters(), randomLetters()); + String email = "sdk+" + SDK_TEST_TAG + randomLetters() + "@cloudinary.com"; ApiResponse user = account.createUser("TestUserJava"+new Date().toString(), email, role, null, subAccountsIds, options); createdUserIds.add(user.get("id").toString()); return user; } private ApiResponse createUser(List subAccountsIds, Account.Role role, Boolean enabled) throws Exception { - String email = String.format("%s@%s.com", randomLetters(), randomLetters()); + String email = "sdk+" + SDK_TEST_TAG + randomLetters() + "@cloudinary.com"; ApiResponse user = account.createUser("TestUserJava"+new Date().toString(), email, role, enabled, subAccountsIds, null); createdUserIds.add(user.get("id").toString()); return user; From c0a910326f9b1e70ce1ab23780c2fab660c43a84 Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Tue, 7 Feb 2023 07:17:58 +0200 Subject: [PATCH 089/150] Add support for `clear_invalid` parameter --- cloudinary-core/src/main/java/com/cloudinary/Util.java | 6 +++++- .../main/java/com/cloudinary/test/AbstractApiTest.java | 10 ++++++++++ .../test/AbstractStructuredMetadataTest.java | 10 ++++++++++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/cloudinary-core/src/main/java/com/cloudinary/Util.java b/cloudinary-core/src/main/java/com/cloudinary/Util.java index 41a95a18..487dd5b0 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Util.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Util.java @@ -172,8 +172,12 @@ public static final void processWriteParameters(Map options, Map putObject("detection", options, params); putObject("similarity_search", options, params); putObject("background_removal", options, params); - if (options.get("auto_tagging") != null) + if (options.get("auto_tagging") != null) { params.put("auto_tagging", ObjectUtils.asFloat(options.get("auto_tagging"))); + } + if (options.get("clear_invalid") != null) { + params.put("clear_invalid", options.get("clear_invalid")); + } } protected static String encodeAccessControl(Object accessControl) { diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java index 45c4a0b3..6fae5a41 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java @@ -725,6 +725,16 @@ public void testDetectionUpdate() { } } + @Test + public void testUpdateResourceClearInvalid() throws Exception { + String fieldId = MetadataTestHelper.addFieldToAccount(api, MetadataTestHelper.newFieldInstance("some_field3" + SUFFIX)).get("external_id").toString(); + String fieldId2 = MetadataTestHelper.addFieldToAccount(api, MetadataTestHelper.newFieldInstance("some_field4" + SUFFIX)).get("external_id").toString(); + Map uploadResult = cloudinary.uploader().upload(SRC_TEST_IMAGE, + ObjectUtils.asMap("tags", UPLOAD_TAGS, "metadata", ObjectUtils.asMap(fieldId, "test"))); + Map apiResult = api.update((String) uploadResult.get("public_id"), ObjectUtils.asMap("clear_invalid", true, "metadata", ObjectUtils.asMap(fieldId2, "test2"))); + assertNotNull(((Map)apiResult.get("metadata")).get(fieldId2)); + } + @Test public void testUpdateCustomCoordinates() throws IOException, Exception { // should update custom coordinates diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractStructuredMetadataTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractStructuredMetadataTest.java index 9aefb64b..b6e541a7 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractStructuredMetadataTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractStructuredMetadataTest.java @@ -6,6 +6,7 @@ import com.cloudinary.api.exceptions.BadRequest; import com.cloudinary.metadata.*; +import com.cloudinary.utils.ObjectUtils; import org.hamcrest.Matchers; import org.junit.*; import org.junit.rules.TestName; @@ -268,6 +269,15 @@ public void testUploaderUpdateMetadata() throws Exception { assertEquals(PRIVATE_PUBLIC_ID, ((List) result2.get("public_ids")).get(0).toString()); } + @Test + public void testUploaderUpdateMetadataClearInvalid() throws Exception { + StringMetadataField field = newFieldInstance("testUploaderUpdateMetadata1"); + ApiResponse fieldResult = addFieldToAccount(field); + String fieldId = fieldResult.get("external_id").toString(); + Map result = cloudinary.uploader().updateMetadata(Collections.singletonMap(fieldId, "123456"), new String[]{PUBLIC_ID}, ObjectUtils.asMap("clear_invalid", true)); + assertNotNull(result); + } + @Test public void testSetField() throws Exception { SetMetadataField field = createSetField("test123"); From 84b11736178acc9f48066d60bc0412615b9213bb Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Tue, 7 Feb 2023 07:19:43 +0200 Subject: [PATCH 090/150] Add support for `media_metadata` parameter --- cloudinary-core/src/main/java/com/cloudinary/Api.java | 2 +- cloudinary-core/src/main/java/com/cloudinary/Util.java | 2 +- .../main/java/com/cloudinary/taglib/CloudinaryUploadTag.java | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/cloudinary-core/src/main/java/com/cloudinary/Api.java b/cloudinary-core/src/main/java/com/cloudinary/Api.java index 4b0308ab..4579fcd1 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Api.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Api.java @@ -163,7 +163,7 @@ public ApiResponse resource(String public_id, Map options) throws Exception { ApiResponse response = callApi(HttpMethod.GET, Arrays.asList("resources", resourceType, type, public_id), ObjectUtils.only(options, "exif", "colors", "faces", "coordinates", "image_metadata", "pages", "phash", "max_results", "quality_analysis", "cinemagraph_analysis", - "accessibility_analysis", "versions"), options); + "accessibility_analysis", "versions", "media_metadata"), options); return response; } diff --git a/cloudinary-core/src/main/java/com/cloudinary/Util.java b/cloudinary-core/src/main/java/com/cloudinary/Util.java index 487dd5b0..6ea073ed 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Util.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Util.java @@ -11,7 +11,7 @@ public class Util { static final String[] BOOLEAN_UPLOAD_OPTIONS = new String[]{"backup", "exif", "faces", "colors", "image_metadata", "use_filename", "unique_filename", "eager_async", "invalidate", "discard_original_filename", "overwrite", "phash", "return_delete_token", "async", "quality_analysis", "cinemagraph_analysis", - "accessibility_analysis", "use_filename_as_display_name", "use_asset_folder_as_public_id_prefix", "unique_display_name"}; + "accessibility_analysis", "use_filename_as_display_name", "use_asset_folder_as_public_id_prefix", "unique_display_name", "media_metadata"}; @SuppressWarnings({"rawtypes", "unchecked"}) public static final Map buildUploadParams(Map options) { diff --git a/cloudinary-taglib/src/main/java/com/cloudinary/taglib/CloudinaryUploadTag.java b/cloudinary-taglib/src/main/java/com/cloudinary/taglib/CloudinaryUploadTag.java index 9157c9db..6b065865 100644 --- a/cloudinary-taglib/src/main/java/com/cloudinary/taglib/CloudinaryUploadTag.java +++ b/cloudinary-taglib/src/main/java/com/cloudinary/taglib/CloudinaryUploadTag.java @@ -60,6 +60,7 @@ public class CloudinaryUploadTag extends SimpleTagSupport { private Boolean overwrite = null; private Boolean phash = null; protected boolean unsigned = false; + private Boolean mediaMetadata = null; public void doTag() throws JspException, IOException { Cloudinary cloudinary = Singleton.getCloudinary(); @@ -92,6 +93,7 @@ public void doTag() throws JspException, IOException { options.put("faces", faces); options.put("colors", colors); options.put("image_metadata", imageMetadata); + options.put("media_metadata", mediaMetadata); options.put("use_filename", useFilename); options.put("unique_filename", uniqueFilename); options.put("eager_async", eagerAsync); From be017b7be2fb0244945ebc41213bea565726657d Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Wed, 15 Feb 2023 07:16:20 +0200 Subject: [PATCH 091/150] Update Hyper SQL version --- samples/photo_album/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/photo_album/pom.xml b/samples/photo_album/pom.xml index 889de220..e30bf14b 100644 --- a/samples/photo_album/pom.xml +++ b/samples/photo_album/pom.xml @@ -102,7 +102,7 @@ org.hsqldb hsqldb - 2.2.9 + 2.7.1 From a5e275ec317172fce5551cea5bb54a0631a70d4c Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Mon, 29 May 2023 12:31:36 +0300 Subject: [PATCH 092/150] Add Search folders functionality --- .../main/java/com/cloudinary/Cloudinary.java | 4 ++++ .../src/main/java/com/cloudinary/Search.java | 2 +- .../java/com/cloudinary/SearchFolders.java | 19 +++++++++++++++++++ .../cloudinary/test/AbstractSearchTest.java | 17 +++++++++++++++++ 4 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 cloudinary-core/src/main/java/com/cloudinary/SearchFolders.java diff --git a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java index 2229fc8f..8e1320c6 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java @@ -59,6 +59,10 @@ public Search search() { return new Search(this); } + public SearchFolders searchFolders() { + return new SearchFolders(this); + } + public static void registerUploaderStrategy(String className) { if (!UPLOAD_STRATEGIES.contains(className)) { UPLOAD_STRATEGIES.add(className); diff --git a/cloudinary-core/src/main/java/com/cloudinary/Search.java b/cloudinary-core/src/main/java/com/cloudinary/Search.java index f16be7eb..1b2bbf28 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Search.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Search.java @@ -10,7 +10,7 @@ public class Search { - private final Api api; + protected final Api api; private ArrayList> sortByParam; private ArrayList aggregateParam; private ArrayList withFieldParam; diff --git a/cloudinary-core/src/main/java/com/cloudinary/SearchFolders.java b/cloudinary-core/src/main/java/com/cloudinary/SearchFolders.java new file mode 100644 index 00000000..1e8bc5bd --- /dev/null +++ b/cloudinary-core/src/main/java/com/cloudinary/SearchFolders.java @@ -0,0 +1,19 @@ +package com.cloudinary; + +import com.cloudinary.api.ApiResponse; +import com.cloudinary.utils.ObjectUtils; + +import java.util.Arrays; +import java.util.Map; + +public class SearchFolders extends Search { + + public SearchFolders(Cloudinary cloudinary) { + super(cloudinary); + } + + public ApiResponse execute() throws Exception { + Map options = ObjectUtils.asMap("content_type", "json"); + return this.api.callApi(Api.HttpMethod.POST, Arrays.asList("folders", "search"), this.toQuery(), options); + } +} diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractSearchTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractSearchTest.java index 67d62967..ac30c2c4 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractSearchTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractSearchTest.java @@ -9,6 +9,9 @@ import java.lang.reflect.Field; import java.util.*; +import static org.hamcrest.Matchers.hasEntry; +import static org.hamcrest.Matchers.hasItem; +import static org.hamcrest.core.AllOf.allOf; import static org.junit.Assert.*; import static org.junit.Assume.assumeNotNull; @@ -19,6 +22,7 @@ abstract public class AbstractSearchTest extends MockableTest { private static final String SEARCH_TAG = "search_test_tag_" + SUFFIX; public static final String[] UPLOAD_TAGS = {SDK_TEST_TAG, SEARCH_TAG}; private static final String SEARCH_TEST = "search_test_" + SUFFIX; + private static final String SEARCH_FOLDER = "search_folder_" + SUFFIX; private static final String SEARCH_TEST_1 = SEARCH_TEST + "_1"; private static final String SEARCH_TEST_2 = SEARCH_TEST + "_2"; private static String SEARCH_TEST_ASSET_ID_1; @@ -44,6 +48,11 @@ public static void setUpClass() throws Exception { public static void tearDownClass() throws Exception { Cloudinary cloudinary = new Cloudinary(); cloudinary.api().deleteResourcesByTag(SEARCH_TAG, null); + try { + cloudinary.api().deleteFolder(SEARCH_FOLDER, null); + } catch (Exception e){ + System.err.println(e.getMessage()); + } } @Before @@ -60,6 +69,14 @@ public void shouldFindResourcesByTag() throws Exception { assertEquals(3, resources.size()); } + @Test + public void shouldFindFolders() throws Exception { + cloudinary.api().createFolder(SEARCH_FOLDER, null); + Map result = cloudinary.searchFolders().expression(String.format("name:%s", SEARCH_FOLDER)).execute(); + final List folders = (List) result.get("folders"); + assertThat(folders, hasItem(hasEntry("name", SEARCH_FOLDER))); + } + @Test public void shouldFindResourceByPublicId() throws Exception { Map result = cloudinary.search().expression(String.format("public_id:%s", SEARCH_TEST_1)).execute(); From b6e5d96491760d81537e1808ed389f7883af6280 Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Thu, 1 Jun 2023 11:49:09 +0300 Subject: [PATCH 093/150] Add `toUrl() to Search API --- .../src/main/java/com/cloudinary/Search.java | 53 +++++++++++++++++-- .../src/main/java/com/cloudinary/Url.java | 39 +++++++------- .../cloudinary/test/AbstractSearchTest.java | 34 +++++++++--- 3 files changed, 98 insertions(+), 28 deletions(-) diff --git a/cloudinary-core/src/main/java/com/cloudinary/Search.java b/cloudinary-core/src/main/java/com/cloudinary/Search.java index 1b2bbf28..652e2cda 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Search.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Search.java @@ -1,8 +1,12 @@ package com.cloudinary; import com.cloudinary.api.ApiResponse; +import com.cloudinary.utils.Base64Coder; import com.cloudinary.utils.ObjectUtils; +import com.cloudinary.utils.StringUtils; +import org.cloudinary.json.JSONObject; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -16,6 +20,8 @@ public class Search { private ArrayList withFieldParam; private HashMap params; + private int ttl = 300; + Search(Cloudinary cloudinary) { this.api = cloudinary.api(); this.params = new HashMap(); @@ -24,6 +30,10 @@ public class Search { this.withFieldParam = new ArrayList(); } + public Search ttl(int ttl) { + this.ttl = ttl; + return this; + } public Search expression(String value) { this.params.put("expression", value); return this; @@ -68,9 +78,15 @@ public Search sortBy(String field, String dir) { public HashMap toQuery() { HashMap queryParams = new HashMap(this.params); - queryParams.put("with_field", withFieldParam); - queryParams.put("sort_by", sortByParam); - queryParams.put("aggregate", aggregateParam); + if (withFieldParam.size() > 0) { + queryParams.put("with_field", withFieldParam); + } + if(sortByParam.size() > 0) { + queryParams.put("sort_by", sortByParam); + } + if(aggregateParam.size() > 0) { + queryParams.put("aggregate", aggregateParam); + } return queryParams; } @@ -78,4 +94,35 @@ public ApiResponse execute() throws Exception { Map options = ObjectUtils.asMap("content_type", "json"); return this.api.callApi(Api.HttpMethod.POST, Arrays.asList("resources", "search"), this.toQuery(), options); } + + + public String toUrl() throws Exception { + return toUrl(null, null); + } + + public String toUrl(String nextCursor) throws Exception { + return toUrl(null, nextCursor); + } + /*** + Creates a signed Search URL that can be used on the client side. + ***/ + public String toUrl(Integer ttl, String nextCursor) throws Exception { + String nextCursorParam = nextCursor; + String apiSecret = api.cloudinary.config.apiSecret; + if (apiSecret == null) throw new IllegalArgumentException("Must supply api_secret"); + if(ttl == null) { + ttl = this.ttl; + } + HashMap queryParams = toQuery(); + if(nextCursorParam == null) { + nextCursorParam = (String) queryParams.get("next_cursor"); + } + queryParams.remove("next_cursor"); + JSONObject json = ObjectUtils.toJSON(queryParams); + String base64Query = Base64Coder.encodeURLSafeString(json.toString()); + String signature = StringUtils.encodeHexString(Util.hash(String.format("%d%s%s", ttl, base64Query, apiSecret), SignatureAlgorithm.SHA256)); + String prefix = Url.unsignedDownloadUrlPrefix(null,api.cloudinary.config); + + return String.format("%s/search/%s/%d/%s%s", prefix, signature, ttl, base64Query,nextCursorParam != null && !nextCursorParam.isEmpty() ? "/"+nextCursorParam : ""); + } } diff --git a/cloudinary-core/src/main/java/com/cloudinary/Url.java b/cloudinary-core/src/main/java/com/cloudinary/Url.java index 360193c0..a45382cd 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Url.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Url.java @@ -339,7 +339,6 @@ public String generate() { } public String generate(String source) { - boolean useRootPath = this.config.useRootPath; if (this.useRootPath != null) { useRootPath = this.useRootPath; @@ -405,8 +404,7 @@ public String generate(String source) { String resourceType = this.resourceType; if (resourceType == null) resourceType = "image"; String finalResourceType = finalizeResourceType(resourceType, type, urlSuffix, useRootPath, config.shorten); - String prefix = unsignedDownloadUrlPrefix(source, config.cloudName, config.privateCdn, config.cdnSubdomain, config.secureCdnSubdomain, config.cname, config.secure, config.secureDistribution); - + String prefix = unsignedDownloadUrlPrefix(source, config); String join = StringUtils.join(new String[]{prefix, finalResourceType, signature, transformationStr, version, source}, "/"); String url = StringUtils.mergeSlashesInUrl(join); @@ -507,49 +505,52 @@ public String finalizeResourceType(String resourceType, String type, String urlS return result; } - public String unsignedDownloadUrlPrefix(String source, String cloudName, boolean privateCdn, boolean cdnSubdomain, Boolean secureCdnSubdomain, String cname, boolean secure, String secureDistribution) { - if (this.config.cloudName.startsWith("/")) { - return "/res" + this.config.cloudName; + public static String unsignedDownloadUrlPrefix(String source, Configuration config) { + if (config.cloudName.startsWith("/")) { + return "/res" + config.cloudName; } - boolean sharedDomain = !this.config.privateCdn; + boolean sharedDomain = !config.privateCdn; String prefix; + String cloudName; + String secureDistribution = config.secureDistribution; + Boolean secureCdnSubdomain = null; - if (this.config.secure) { - if (StringUtils.isEmpty(this.config.secureDistribution) || this.config.secureDistribution.equals(Cloudinary.OLD_AKAMAI_SHARED_CDN)) { - secureDistribution = this.config.privateCdn ? this.config.cloudName + "-res.cloudinary.com" : Cloudinary.SHARED_CDN; + if (config.secure) { + if (StringUtils.isEmpty(config.secureDistribution) || config.secureDistribution.equals(Cloudinary.OLD_AKAMAI_SHARED_CDN)) { + secureDistribution = config.privateCdn ? config.cloudName + "-res.cloudinary.com" : Cloudinary.SHARED_CDN; } if (!sharedDomain) { sharedDomain = secureDistribution.equals(Cloudinary.SHARED_CDN); } if (secureCdnSubdomain == null && sharedDomain) { - secureCdnSubdomain = this.config.cdnSubdomain; + secureCdnSubdomain = config.cdnSubdomain; } if (secureCdnSubdomain != null && secureCdnSubdomain == true) { - secureDistribution = this.config.secureDistribution.replace("res.cloudinary.com", "res-" + shard(source) + ".cloudinary.com"); + secureDistribution = config.secureDistribution.replace("res.cloudinary.com", "res-" + shard(source) + ".cloudinary.com"); } prefix = "https://" + secureDistribution; - } else if (StringUtils.isNotBlank(this.config.cname)) { - String subdomain = this.config.cdnSubdomain ? "a" + shard(source) + "." : ""; - prefix = "http://" + subdomain + this.config.cname; + } else if (StringUtils.isNotBlank(config.cname)) { + String subdomain = config.cdnSubdomain ? "a" + shard(source) + "." : ""; + prefix = "http://" + subdomain + config.cname; } else { String protocol = "http://"; - cloudName = this.config.privateCdn ? this.config.cloudName + "-" : ""; + cloudName = config.privateCdn ? config.cloudName + "-" : ""; String res = "res"; - String subdomain = this.config.cdnSubdomain ? "-" + shard(source) : ""; + String subdomain = config.cdnSubdomain ? "-" + shard(source) : ""; String domain = ".cloudinary.com"; prefix = StringUtils.join(new String[]{protocol, cloudName, res, subdomain, domain}, ""); } if (sharedDomain) { - prefix += "/" + this.config.cloudName; + prefix += "/" + config.cloudName; } return prefix; } - private String shard(String input) { + private static String shard(String input) { CRC32 crc32 = new CRC32(); crc32.update(Util.getUTF8Bytes(input)); return String.valueOf((crc32.getValue() % 5 + 5) % 5 + 1); diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractSearchTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractSearchTest.java index ac30c2c4..1d0a2094 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractSearchTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractSearchTest.java @@ -1,7 +1,9 @@ package com.cloudinary.test; import com.cloudinary.Cloudinary; +import com.cloudinary.Configuration; import com.cloudinary.Search; +import com.cloudinary.api.ApiResponse; import com.cloudinary.utils.ObjectUtils; import org.junit.*; import org.junit.rules.TestName; @@ -71,10 +73,14 @@ public void shouldFindResourcesByTag() throws Exception { @Test public void shouldFindFolders() throws Exception { - cloudinary.api().createFolder(SEARCH_FOLDER, null); - Map result = cloudinary.searchFolders().expression(String.format("name:%s", SEARCH_FOLDER)).execute(); - final List folders = (List) result.get("folders"); - assertThat(folders, hasItem(hasEntry("name", SEARCH_FOLDER))); + Map createFolderResult = cloudinary.api().createFolder(SEARCH_FOLDER, null); + Thread.sleep(3000); + if ((Boolean) createFolderResult.get("success")) { + Map result = cloudinary.searchFolders().expression(String.format("name:%s", SEARCH_FOLDER)).execute(); + System.out.println("SUCCESS!"); + final List folders = (List) result.get("folders"); + assertThat(folders, hasItem(hasEntry("name", SEARCH_FOLDER))); + } } @Test @@ -152,7 +158,23 @@ public void shouldPaginateResourcesLimitedByTagAndOrderdByAscendingPublicId() th assertEquals(3, result.get("total_count")); assertEquals(SEARCH_TEST_2, resources.get(0).get("public_id")); assertNull(result.get("next_cursor")); + } - + @Test + public void testShouldBuildSearchUrl() throws Exception { + String nextCursor = "db27cfb02b3f69cb39049969c23ca430c6d33d5a3a7c3ad1d870c54e1a54ee0faa5acdd9f6d288666986001711759d10"; + Cloudinary cloudinaryToSearch = new Cloudinary("cloudinary://key:secret@test123"); + cloudinaryToSearch.config.secure = true; + + Search search = cloudinaryToSearch.search().expression("resource_type:image AND tags=kitten AND uploaded_at>1d AND bytes>1m").sortBy("public_id", "desc").maxResults(30); + String base64Query = "eyJleHByZXNzaW9uIjoicmVzb3VyY2VfdHlwZTppbWFnZSBBTkQgdGFncz1raXR0ZW4gQU5EIHVwbG9hZGVkX2F0PjFkIEFORCBieXRlcz4xbSIsIm1heF9yZXN1bHRzIjozMCwic29ydF9ieSI6W3sicHVibGljX2lkIjoiZGVzYyJ9XX0="; + String ttl300Signature = "431454b74cefa342e2f03e2d589b2e901babb8db6e6b149abf25bc0dd7ab20b7"; + String ttl1000Signature = "25b91426a37d4f633a9b34383c63889ff8952e7ffecef29a17d600eeb3db0db7"; + + assertEquals(String.format("https://res.cloudinary.com/%s/search/%s/%d/%s", cloudinaryToSearch.config.cloudName, ttl300Signature, 300, base64Query), search.toUrl()); + assertEquals(String.format("https://res.cloudinary.com/%s/search/%s/%d/%s/%s", cloudinaryToSearch.config.cloudName, ttl300Signature, 300, base64Query, nextCursor), search.toUrl(nextCursor)); + assertEquals(String.format("https://res.cloudinary.com/%s/search/%s/%d/%s/%s", cloudinaryToSearch.config.cloudName, ttl1000Signature, 1000, base64Query, nextCursor), search.toUrl(1000, nextCursor)); + cloudinaryToSearch.config.privateCdn = true; + assertEquals(String.format("https://%s-res.cloudinary.com/search/%s/%d/%s", cloudinaryToSearch.config.cloudName, ttl300Signature, 300, base64Query), search.toUrl(300, "")); } -} +} \ No newline at end of file From ec9362c9a436105f13ef8652aaf463ec7a5038c1 Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Wed, 5 Jul 2023 16:39:39 +0300 Subject: [PATCH 094/150] Add visual search support --- cloudinary-core/src/main/java/com/cloudinary/Api.java | 11 +++++++++++ .../src/main/java/com/cloudinary/Util.java | 5 ++++- .../java/com/cloudinary/test/AbstractApiTest.java | 10 ++++++++++ .../com/cloudinary/test/AbstractUploaderTest.java | 4 +++- 4 files changed, 28 insertions(+), 2 deletions(-) diff --git a/cloudinary-core/src/main/java/com/cloudinary/Api.java b/cloudinary-core/src/main/java/com/cloudinary/Api.java index 4579fcd1..828b821b 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Api.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Api.java @@ -92,6 +92,17 @@ public ApiResponse resources(Map options) throws Exception { return response; } + public ApiResponse visualSearch(Map options) throws Exception { + List uri = new ArrayList(); + uri.add("resources/visual_search"); + uri.add("image"); + if (options.get("text") == null && options.get("image_asset_id") == null && options.get("image_url") == null) { + throw new IllegalArgumentException("Must supply image file, image url, image asset id or text"); + } + ApiResponse response = callApi(HttpMethod.GET, uri, options, options); + return response; + } + public ApiResponse resourcesByTag(String tag, Map options) throws Exception { if (options == null) options = ObjectUtils.emptyMap(); String resourceType = ObjectUtils.asString(options.get("resource_type"), "image"); diff --git a/cloudinary-core/src/main/java/com/cloudinary/Util.java b/cloudinary-core/src/main/java/com/cloudinary/Util.java index 6ea073ed..553ae203 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Util.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Util.java @@ -11,7 +11,7 @@ public class Util { static final String[] BOOLEAN_UPLOAD_OPTIONS = new String[]{"backup", "exif", "faces", "colors", "image_metadata", "use_filename", "unique_filename", "eager_async", "invalidate", "discard_original_filename", "overwrite", "phash", "return_delete_token", "async", "quality_analysis", "cinemagraph_analysis", - "accessibility_analysis", "use_filename_as_display_name", "use_asset_folder_as_public_id_prefix", "unique_display_name", "media_metadata"}; + "accessibility_analysis", "use_filename_as_display_name", "use_asset_folder_as_public_id_prefix", "unique_display_name", "media_metadata", "visual_search"}; @SuppressWarnings({"rawtypes", "unchecked"}) public static final Map buildUploadParams(Map options) { @@ -178,6 +178,9 @@ public static final void processWriteParameters(Map options, Map if (options.get("clear_invalid") != null) { params.put("clear_invalid", options.get("clear_invalid")); } + if(options.get("visual_search") != null) { + params.put("visual_search", options.get("visual_search")); + } } protected static String encodeAccessControl(Object accessControl) { diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java index 6fae5a41..24cc490d 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java @@ -1222,4 +1222,14 @@ public void testFolderDecoupling() { assertEquals("new_asset_folder", params.get("asset_folder")); assertEquals(true, params.get("unique_display_name")); } + + @Test + public void testVisualSearch() { + //TODO: Need to build a unit testing infrastructure + Map params = new HashMap(); + Map options = asMap( + "visual_search", true); + Util.processWriteParameters(options, params); + assertEquals(true, params.get("visual_search")); + } } diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java index 89b502fb..1ce9a4b8 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java @@ -813,7 +813,8 @@ public void testUploadFolderDecoupling() { "public_id_prefix", "test_id_prefix", "asset_folder", "asset_folder_test", "display_name", "display_name_test", - "use_asset_folder_as_public_id_prefix", true); + "use_asset_folder_as_public_id_prefix", true, + "visual_search", true); Map uploadParams = Util.buildUploadParams(options); Assert.assertEquals("test_id_prefix", uploadParams.get("public_id_prefix")); @@ -821,5 +822,6 @@ public void testUploadFolderDecoupling() { Assert.assertEquals("asset_folder_test", uploadParams.get("asset_folder")); Assert.assertEquals("display_name_test", uploadParams.get("display_name")); Assert.assertEquals(true, uploadParams.get("use_asset_folder_as_public_id_prefix")); + Assert.assertEquals(true, uploadParams.get("visual_search")); } } From c62bba79f4da8715140c2f49506653ebd3b95f40 Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Tue, 8 Aug 2023 14:49:51 +0300 Subject: [PATCH 095/150] Fix Provisioning tests --- .travis.yml | 2 +- .../test/AbstractAccountApiTest.java | 44 +++++++++++++++++++ .../com/cloudinary/test/MockableTest.java | 6 +++ 3 files changed, 51 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 15fbae01..510d55ae 100644 --- a/.travis.yml +++ b/.travis.yml @@ -30,7 +30,7 @@ branches: before_script: ./gradlew createTestSubAccount -PmoduleName=${MODULE} # ciTest is configured to skip the various timeout tests that don't work in travis -script: source tools/cloudinary_url.txt && ./gradlew -DCLOUDINARY_URL=$CLOUDINARY_URL -DCLOUDINARY_ACCOUNT_URL=$CLOUDINARY_ACCOUNT_URL ciTest -p cloudinary-${MODULE} -i +script: source tools/cloudinary_url.txt && ./gradlew -DCLOUDINARY_URL=$CLOUDINARY_URL ciTest -p cloudinary-${MODULE} -i notifications: diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractAccountApiTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractAccountApiTest.java index 8dc30fc9..7513907a 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractAccountApiTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractAccountApiTest.java @@ -15,6 +15,7 @@ import static java.util.Collections.singletonMap; import static junit.framework.TestCase.assertTrue; import static org.junit.Assert.*; +import static org.junit.Assume.assumeTrue; public abstract class AbstractAccountApiTest extends MockableTest { private static Random rand = new Random(); @@ -35,12 +36,14 @@ public static void setUpClass() { @Before public void setUp() throws Exception { + assumeCloudinaryAccountURLExist(); System.out.println("Running " + this.getClass().getName() + "." + currentTest.getMethodName()); this.account = new Account(new Cloudinary()); } @AfterClass public static void tearDownClass() { + assumeCloudinaryAccountURLExist(); System.out.println("Start TearDownClass"); Account account = new Account(new Cloudinary()); for (String createdSubAccountId : createdSubAccountIds) { @@ -71,6 +74,7 @@ public static void tearDownClass() { @Test public void testPassingCredentialsThroughOptions() throws Exception { + assumeCloudinaryAccountURLExist(); int exceptions = 0; Map map = singletonMap("provisioning_api_secret", new Object()) ; @@ -104,6 +108,7 @@ public void testPassingCredentialsThroughOptions() throws Exception { // Sub accounts tests @Test public void testGetSubAccount() throws Exception { + assumeCloudinaryAccountURLExist(); ApiResponse accountResponse = createSubAccount(); ApiResponse account = this.account.subAccount(accountResponse.get("id").toString(), null); assertNotNull(account); @@ -111,6 +116,7 @@ public void testGetSubAccount() throws Exception { @Test public void testGetSubAccounts() throws Exception { + assumeCloudinaryAccountURLExist(); createSubAccount(); ApiResponse accounts = account.subAccounts(null, null, null, null); assertNotNull(accounts); @@ -119,6 +125,7 @@ public void testGetSubAccounts() throws Exception { @Test public void testCreateSubAccount() throws Exception { + assumeCloudinaryAccountURLExist(); ApiResponse result = createSubAccount(); assertNotNull(result); @@ -135,6 +142,7 @@ public void testCreateSubAccount() throws Exception { @Test public void testUpdateSubAccount() throws Exception { + assumeCloudinaryAccountURLExist(); ApiResponse subAccount = createSubAccount(); String newCloudName = randomLetters(); ApiResponse result = account.updateSubAccount(subAccount.get("id").toString(), null, newCloudName, Collections.emptyMap(), null, null); @@ -144,6 +152,7 @@ public void testUpdateSubAccount() throws Exception { @Test public void testDeleteSubAccount() throws Exception { + assumeCloudinaryAccountURLExist(); ApiResponse createResult = createSubAccount(); String id = createResult.get("id").toString(); ApiResponse result = account.deleteSubAccount(id, null); @@ -155,6 +164,7 @@ public void testDeleteSubAccount() throws Exception { // Users test @Test public void testGetUser() throws Exception { + assumeCloudinaryAccountURLExist(); ApiResponse user = createUser(); String userId = user.get("id").toString(); ApiResponse result = account.user(userId, null); @@ -165,6 +175,7 @@ public void testGetUser() throws Exception { @Test public void testGetUsers() throws Exception { + assumeCloudinaryAccountURLExist(); String user1Id = createUser(Account.Role.MASTER_ADMIN).get("id").toString(); String user2Id = createUser(Account.Role.MASTER_ADMIN).get("id").toString(); ApiResponse result = account.users(null, Arrays.asList(user1Id, user2Id), null, null, null); @@ -185,6 +196,7 @@ public void testGetUsers() throws Exception { @Test public void testGetPendingUsers() throws Exception { + assumeCloudinaryAccountURLExist(); String id = createUser(Account.Role.BILLING).get("id").toString(); ApiResponse pending = account.users(true, Collections.singletonList(id), null, null, null); @@ -199,6 +211,7 @@ public void testGetPendingUsers() throws Exception { @Test public void testGetUsersByPrefix() throws Exception { + assumeCloudinaryAccountURLExist(); final long timeMillis = System.currentTimeMillis(); final String userName = String.format("SDK TEST Get Users By Prefix %d", timeMillis); final String userEmail = String.format("sdk-test-get-users-by-prefix+%d@cloudinary.com", timeMillis); @@ -217,6 +230,7 @@ public void testGetUsersByPrefix() throws Exception { @Test public void testGetUsersBySubAccountIds() throws Exception { + assumeCloudinaryAccountURLExist(); ApiResponse subAccount = createSubAccount(); final String subAccountId = subAccount.get("id").toString(); @@ -235,6 +249,7 @@ public void testGetUsersBySubAccountIds() throws Exception { @Test public void testGetUsersThrowsWhenSubAccountIdDoesntExist() throws Exception { + assumeCloudinaryAccountURLExist(); final String subAccountId = randomLetters(); expectedException.expectMessage("Cannot find sub account with id " + subAccountId); account.users(true, null, null, subAccountId, null); @@ -242,6 +257,7 @@ public void testGetUsersThrowsWhenSubAccountIdDoesntExist() throws Exception { @Test public void testCreateUser() throws Exception { + assumeCloudinaryAccountURLExist(); ApiResponse createResult = createSubAccount(); ApiResponse result = createUser(Collections.singletonList(createResult.get("id").toString())); assertNotNull(result); @@ -249,6 +265,7 @@ public void testCreateUser() throws Exception { @Test public void testCreateUserWithOptions() throws Exception { + assumeCloudinaryAccountURLExist(); ApiResponse createResult = createSubAccount(); ApiResponse result = createUser(Collections.singletonList(createResult.get("id").toString()), ObjectUtils.emptyMap()); assertNotNull(result); @@ -256,6 +273,7 @@ public void testCreateUserWithOptions() throws Exception { @Test public void testCreateUserEnabled() throws Exception { + assumeCloudinaryAccountURLExist(); ApiResponse createResult = createSubAccount(); ApiResponse result = createUser(Collections.singletonList(createResult.get("id").toString()), true); assertTrue((Boolean) result.get("enabled")); @@ -263,6 +281,7 @@ public void testCreateUserEnabled() throws Exception { @Test public void testCreateUserDisabled() throws Exception { + assumeCloudinaryAccountURLExist(); ApiResponse createResult = createSubAccount(); ApiResponse result = createUser(Collections.singletonList(createResult.get("id").toString()), false); assertFalse((Boolean) result.get("enabled")); @@ -270,6 +289,7 @@ public void testCreateUserDisabled() throws Exception { @Test public void testUpdateUser() throws Exception { + assumeCloudinaryAccountURLExist(); ApiResponse user = createUser(Account.Role.ADMIN); String userId = user.get("id").toString(); String newName = randomLetters(); @@ -282,6 +302,7 @@ public void testUpdateUser() throws Exception { @Test public void testUpdateUserEnabled() throws Exception { + assumeCloudinaryAccountURLExist(); ApiResponse user = createUser(Account.Role.ADMIN); String userId = user.get("id").toString(); String newName = randomLetters(); @@ -294,6 +315,7 @@ public void testUpdateUserEnabled() throws Exception { @Test public void testUpdateUserDisabled() throws Exception { + assumeCloudinaryAccountURLExist(); ApiResponse user = createUser(Account.Role.ADMIN); String userId = user.get("id").toString(); String newName = randomLetters(); @@ -306,6 +328,7 @@ public void testUpdateUserDisabled() throws Exception { @Test public void testDeleteUser() throws Exception { + assumeCloudinaryAccountURLExist(); ApiResponse user = createUser(Collections.emptyList()); String id = user.get("id").toString(); ApiResponse result = account.deleteUser(id, null); @@ -316,12 +339,14 @@ public void testDeleteUser() throws Exception { // groups @Test public void testCreateUserGroup() throws Exception { + assumeCloudinaryAccountURLExist(); ApiResponse group = createGroup(); assertNotNull(group); } @Test public void testUpdateUserGroup() throws Exception { + assumeCloudinaryAccountURLExist(); ApiResponse group = createGroup(); String newName = randomLetters(); ApiResponse result = account.updateUserGroup(group.get("id").toString(), newName, null); @@ -330,6 +355,7 @@ public void testUpdateUserGroup() throws Exception { @Test public void testDeleteUserGroup() throws Exception { + assumeCloudinaryAccountURLExist(); ApiResponse group = createGroup(); String id = group.get("id").toString(); ApiResponse result = account.deleteUserGroup(id, null); @@ -340,6 +366,7 @@ public void testDeleteUserGroup() throws Exception { @Test public void testAddUserToUserGroup() throws Exception { + assumeCloudinaryAccountURLExist(); ApiResponse user = createUser(); ApiResponse group = createGroup(); String userId = user.get("id").toString(); @@ -350,6 +377,7 @@ public void testAddUserToUserGroup() throws Exception { @Test public void testRemoveUserFromUserGroup() throws Exception { + assumeCloudinaryAccountURLExist(); ApiResponse user = createUser(Account.Role.MEDIA_LIBRARY_ADMIN); ApiResponse group = createGroup(); String groupId = group.get("id").toString(); @@ -362,6 +390,7 @@ public void testRemoveUserFromUserGroup() throws Exception { @Test public void testListUserGroups() throws Exception { + assumeCloudinaryAccountURLExist(); createGroup(); ApiResponse result = account.userGroups(); assertNotNull(result); @@ -370,6 +399,7 @@ public void testListUserGroups() throws Exception { @Test public void testListUserGroup() throws Exception { + assumeCloudinaryAccountURLExist(); ApiResponse group = createGroup(); ApiResponse result = account.userGroup(group.get("id").toString(), null); assertNotNull(result); @@ -377,6 +407,7 @@ public void testListUserGroup() throws Exception { @Test public void testListUsersInGroup() throws Exception { + assumeCloudinaryAccountURLExist(); ApiResponse user1 = createUser(); ApiResponse user2 = createUser(); ApiResponse group = createGroup(); @@ -395,6 +426,7 @@ public void testListUsersInGroup() throws Exception { // Helpers private ApiResponse createGroup() throws Exception { + assumeCloudinaryAccountURLExist(); String name = randomLetters(); ApiResponse userGroup = account.createUserGroup(name); createdGroupIds.add(userGroup.get("id").toString()); @@ -402,31 +434,38 @@ private ApiResponse createGroup() throws Exception { } private ApiResponse createUser() throws Exception { + assumeCloudinaryAccountURLExist(); return createUser(Collections.emptyList()); } private ApiResponse createUser(Account.Role role) throws Exception { + assumeCloudinaryAccountURLExist(); return createUser(Collections.emptyList(), role); } private ApiResponse createUser(List subAccountsIds) throws Exception { + assumeCloudinaryAccountURLExist(); return createUser(subAccountsIds, Account.Role.BILLING); } private ApiResponse createUser(List subAccountsIds, Map options) throws Exception { + assumeCloudinaryAccountURLExist(); return createUser(subAccountsIds, Account.Role.BILLING, options); } private ApiResponse createUser(List subAccountsIds, Boolean enabled) throws Exception { + assumeCloudinaryAccountURLExist(); return createUser(subAccountsIds, Account.Role.BILLING, enabled); } private ApiResponse createUser(List subAccountsIds, Account.Role role) throws Exception { + assumeCloudinaryAccountURLExist(); String email = "sdk+" + SDK_TEST_TAG + randomLetters() + "@cloudinary.com"; return createUser("TestName", email, role, subAccountsIds); } private ApiResponse createUser(List subAccountsIds, Account.Role role, Map options) throws Exception { + assumeCloudinaryAccountURLExist(); String email = "sdk+" + SDK_TEST_TAG + randomLetters() + "@cloudinary.com"; ApiResponse user = account.createUser("TestUserJava"+new Date().toString(), email, role, null, subAccountsIds, options); createdUserIds.add(user.get("id").toString()); @@ -434,6 +473,7 @@ private ApiResponse createUser(List subAccountsIds, Account.Role role, M } private ApiResponse createUser(List subAccountsIds, Account.Role role, Boolean enabled) throws Exception { + assumeCloudinaryAccountURLExist(); String email = "sdk+" + SDK_TEST_TAG + randomLetters() + "@cloudinary.com"; ApiResponse user = account.createUser("TestUserJava"+new Date().toString(), email, role, enabled, subAccountsIds, null); createdUserIds.add(user.get("id").toString()); @@ -441,12 +481,14 @@ private ApiResponse createUser(List subAccountsIds, Account.Role role, B } private ApiResponse createUser(final String name, String email, Account.Role role, List subAccountsIds) throws Exception { + assumeCloudinaryAccountURLExist(); ApiResponse user = account.createUser(name, email, role, subAccountsIds, null); createdUserIds.add(user.get("id").toString()); return user; } private void deleteUser(String userId){ + assumeCloudinaryAccountURLExist(); try { account.deleteUser(userId, null); createdUserIds.remove(userId); @@ -457,12 +499,14 @@ private void deleteUser(String userId){ private ApiResponse createSubAccount() throws Exception { + assumeCloudinaryAccountURLExist(); ApiResponse subAccount = account.createSubAccount(randomLetters(), null, emptyMap(), true, null); createdSubAccountIds.add(subAccount.get("id").toString()); return subAccount; } private static String randomLetters() { + assumeCloudinaryAccountURLExist(); StringBuilder sb = new StringBuilder(); for (int i = 0; i < 10; i++) { sb.append((char) ('a' + rand.nextInt('z' - 'a' + 1))); diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/MockableTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/MockableTest.java index 2308d3c2..92b272dd 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/MockableTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/MockableTest.java @@ -69,4 +69,10 @@ protected static boolean shouldTestFeature(String feature) { List sdkFeaturesList = Arrays.asList(sdkFeatures.split(",")); return sdkFeatures.contains(feature.toLowerCase()) || (sdkFeaturesList.size() == 1 && sdkFeaturesList.get(0).equalsIgnoreCase(Feature.ALL)); } + + static protected boolean assumeCloudinaryAccountURLExist() { + String cloudinaryAccountUrl = System.getProperty("CLOUDINARY_ACCOUNT_URL", System.getenv("CLOUDINARY_ACCOUNT_URL")); + assumeTrue(String.format("Use CLOUDINARY_ACCOUNT_URL environment variable to enable tests"), cloudinaryAccountUrl != null); + return cloudinaryAccountUrl != null; + } } From f8e0c32c8d19388c120c0c72a93fcff6b363b661 Mon Sep 17 00:00:00 2001 From: adimiz1 Date: Tue, 8 Aug 2023 18:41:15 +0300 Subject: [PATCH 096/150] Version 1.34.0 --- CHANGELOG.md | 11 +++++++++++ README.md | 4 ++-- .../src/main/java/com/cloudinary/Cloudinary.java | 2 +- gradle.properties | 2 +- 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7bb2294c..8c12c7b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,14 @@ + +1.34.0 / 2023-08-08 +=================== + + * Add visual search support + * Add `toUrl() to Search API + * Add Search folders functionality + * Update Hyper SQL version + * Add support for `media_metadata` parameter + * Add support for `clear_invalid` parameter + 1.33.0 / 2022-09-12 ================== diff --git a/README.md b/README.md index 48f45ecd..8f66ff78 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ For the complete documentation, see the [Java SDK Guide](https://cloudinary.com/ ## Version Support | SDK Version | Java 6+ | |----------------|---------| -| 1.1.0 - 1.33.0 | V | +| 1.1.0 - 1.34.0 | V | ## Installation The cloudinary_java library is available in [Maven Central](https://mvnrepository.com/artifact/com.cloudinary/cloudinary-core). To use it, add the following dependency to your pom.xml : @@ -36,7 +36,7 @@ The cloudinary_java library is available in [Maven Central](https://mvnrepositor com.cloudinary cloudinary-http44 - 1.33.0 + 1.34.0 ``` diff --git a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java index 8e1320c6..4ba99f40 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java @@ -38,7 +38,7 @@ public class Cloudinary { public final static String AKAMAI_SHARED_CDN = "res.cloudinary.com"; public final static String SHARED_CDN = AKAMAI_SHARED_CDN; - public final static String VERSION = "1.33.0"; + public final static String VERSION = "1.34.0"; static String USER_AGENT_PREFIX = "CloudinaryJava"; public final static String USER_AGENT_JAVA_VERSION = "(Java " + System.getProperty("java.version") + ")"; diff --git a/gradle.properties b/gradle.properties index 2fac0474..7f41fc8c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,7 +13,7 @@ developerEmail=info@cloudinary.com # These two properties must use these exact names to be compatible with 'gradle install' plugin. group=com.cloudinary -version=1.33.0 +version=1.34.0 gnsp.disableApplyOnlyOnRootProjectEnforcement=true From 25c9cc77fdc17387b5aff5dd78b44aa913dfa298 Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Wed, 9 Aug 2023 15:24:38 +0300 Subject: [PATCH 097/150] Add support for `on_success` upload parameter --- cloudinary-core/src/main/java/com/cloudinary/Util.java | 2 +- .../java/com/cloudinary/test/AbstractUploaderTest.java | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/cloudinary-core/src/main/java/com/cloudinary/Util.java b/cloudinary-core/src/main/java/com/cloudinary/Util.java index 553ae203..19ae2c71 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Util.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Util.java @@ -39,7 +39,7 @@ public static final Map buildUploadParams(Map options) { params.put("public_id_prefix", (String) options.get("public_id_prefix")); params.put("asset_folder", (String) options.get("asset_folder")); params.put("display_name", (String) options.get("display_name")); - + params.put("on_success", (String) options.get("on_success")); Object responsive_breakpoints = options.get("responsive_breakpoints"); if (responsive_breakpoints != null) { params.put("responsive_breakpoints", JSONObject.wrap(responsive_breakpoints)); diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java index 1ce9a4b8..bf590e13 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java @@ -763,6 +763,13 @@ public void testAccessControl() throws ParseException, IOException { assertEquals("2019-03-21T22:00:00Z", accessControlResponse.get(0).get("end")); } + @Test + public void testOnSuccessScript() throws Exception { + String tags = "[\"autocaption\"" + ",\"" + SDK_TEST_TAG + "\",\"" + UPLOADER_TAG + "\"]"; + Map result = cloudinary.uploader().upload(SRC_TEST_IMAGE, asMap("on_success", "current_asset.update({tags:" + tags + "});")); + assertTrue(((List)result.get("tags")).contains("autocaption")); + } + @Test public void testQualityAnalysis() throws IOException { Map result = cloudinary.uploader().upload(SRC_TEST_IMAGE, asMap("quality_analysis", true, "tags", Arrays.asList(SDK_TEST_TAG, UPLOADER_TAG))); From 9c2e22bfdf0bb4e8850987f0c4f60cfcd6747fab Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Mon, 18 Sep 2023 10:59:31 +0300 Subject: [PATCH 098/150] Add test for fetch video overlay --- .../src/test/java/com/cloudinary/test/CloudinaryTest.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java b/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java index c46672d4..8782dfc3 100644 --- a/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java +++ b/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java @@ -1257,7 +1257,9 @@ public void testOverlayOptions() { new FetchLayer().url("https://test").resourceType("image"), "fetch:aHR0cHM6Ly90ZXN0", new FetchLayer().url("https://test"), - "fetch:aHR0cHM6Ly90ZXN0"}; + "fetch:aHR0cHM6Ly90ZXN0", + new FetchLayer().url("https://test").resourceType("video"), + "video:fetch:aHR0cHM6Ly90ZXN0"}; for (int i = 0; i < tests.length; i += 2) { Object layer = tests[i]; From 3e97239ab357457c847727a1e119c00e12a39ce7 Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Wed, 11 Oct 2023 14:11:05 +0300 Subject: [PATCH 099/150] Update analytics token --- .../java/com/cloudinary/utils/Analytics.java | 27 +++++++++++++++---- .../cloudinary/analytics/AnalyticsTest.java | 26 +++++++++--------- 2 files changed, 35 insertions(+), 18 deletions(-) diff --git a/cloudinary-core/src/main/java/com/cloudinary/utils/Analytics.java b/cloudinary-core/src/main/java/com/cloudinary/utils/Analytics.java index e20ae5fa..b0027889 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/utils/Analytics.java +++ b/cloudinary-core/src/main/java/com/cloudinary/utils/Analytics.java @@ -8,18 +8,23 @@ public class Analytics { private String sdkTokenQueryKey = "_a"; //sdkTokenQueryKey private String sdkQueryDelimiter = "="; - public String algoVersion = "A"; + public String algoVersion = "C"; + public String prodcut = "A"; public String SDKCode = ""; // Java = G, Android = F public String SDKSemver = ""; // Calculate the SDK version . public String techVersion = ""; // Calculate the Java version. + public String osType; + public String osVersion; public Analytics() { - this("G", Cloudinary.VERSION,System.getProperty("java.version")); + this("G", Cloudinary.VERSION,System.getProperty("java.version"), "Z", "0.0"); } - public Analytics(String sdkCode, String sdkVersion, String techVersion) { + public Analytics(String sdkCode, String sdkVersion, String techVersion, String osType, String osVersion) { this.SDKCode = sdkCode; this.SDKSemver = sdkVersion; this.techVersion = techVersion; + this.osType = osType; + this.osVersion = osVersion; } public Analytics setSDKCode(String SDKCode) { @@ -43,7 +48,7 @@ public Analytics setTechVersion(String techVersion) { */ public String toQueryParam() { try { - return sdkTokenQueryKey + sdkQueryDelimiter + getAlgorithmVersion() + getSDKType() + getSDKVersion() + getTechVersion() + getSDKFeatureCode(); + return sdkTokenQueryKey + sdkQueryDelimiter + getAlgorithmVersion() + prodcut + getSDKType() + getSDKVersion() + getTechVersion() + getOsType() + getOsVersion() + getSDKFeatureCode(); } catch (Exception e) { return sdkTokenQueryKey + sdkQueryDelimiter + "E"; } @@ -52,18 +57,30 @@ public String toQueryParam() { private String getTechVersion() throws Exception { String[] techVersionString = techVersion.split("_"); String[] versions = techVersionString[0].split("\\."); + return versionArrayToString(versions); + } + + private String versionArrayToString(String[] versions) throws Exception { if (versions.length > 2) { versions = Arrays.copyOf(versions, versions.length - 1); } return getPaddedString(StringUtils.join(versions, ".")); } + private String getOsType() { + return (osType != null) ? osType : "Z"; //System.getProperty("os.name"); + } + + private String getOsVersion() throws Exception { + return (osVersion != null) ? versionArrayToString(osVersion.split("\\.")) : versionArrayToString(System.getProperty("os.version").split("\\.")); + } + private String getSDKType() { return SDKCode; } private String getAlgorithmVersion() { - return "A"; + return algoVersion; } private String getSDKFeatureCode() { diff --git a/cloudinary-core/src/test/java/com/cloudinary/analytics/AnalyticsTest.java b/cloudinary-core/src/test/java/com/cloudinary/analytics/AnalyticsTest.java index b45e76e0..fa277c15 100644 --- a/cloudinary-core/src/test/java/com/cloudinary/analytics/AnalyticsTest.java +++ b/cloudinary-core/src/test/java/com/cloudinary/analytics/AnalyticsTest.java @@ -29,19 +29,19 @@ public void testEncodeVersion() { analytics.setSDKSemver("1.24.0"); analytics.setTechVersion("12.0.0"); String result = analytics.toQueryParam(); - Assert.assertEquals(result, "_a=AGAlhAM0"); + Assert.assertEquals(result, "_a=CAGAlhAMZAA0"); analytics.setSDKSemver("12.0"); result = analytics.toQueryParam(); - Assert.assertEquals(result, "_a=AGAMAM0"); + Assert.assertEquals(result, "_a=CAGAMAMZAA0"); analytics.setSDKSemver("43.21.26"); result = analytics.toQueryParam(); - Assert.assertEquals(result, "_a=AG///AM0"); + Assert.assertEquals(result, "_a=CAG///AMZAA0"); analytics.setSDKSemver("0.0.0"); result = analytics.toQueryParam(); - Assert.assertEquals(result, "_a=AGAAAAM0"); + Assert.assertEquals(result, "_a=CAGAAAAMZAA0"); analytics.setSDKSemver("43.21.27"); result = analytics.toQueryParam(); @@ -51,17 +51,17 @@ public void testEncodeVersion() { @Test public void testToQueryParam() { - Analytics analytics = new Analytics("F", "2.0.0", "1.8.0"); + Analytics analytics = new Analytics("F", "2.0.0", "1.8.0", "Z", "1.34.0"); String result = analytics.toQueryParam(); - Assert.assertEquals(result, "_a=AFAACMh0"); + Assert.assertEquals(result, "_a=CAFAACMhZ1J0"); } @Test public void testUrlWithAnalytics() { cloudinary.config.analytics = true; - cloudinary.setAnalytics(new Analytics("F", "2.0.0", "1.8.0")); + cloudinary.setAnalytics(new Analytics("F", "2.0.0", "1.8.0", "Z", "1.34.0")); String url = cloudinary.url().generate("test"); - Assert.assertEquals(url, "http://res.cloudinary.com/test123/image/upload/test?_a=AFAACMh0"); + Assert.assertEquals(url, "http://res.cloudinary.com/test123/image/upload/test?_a=CAFAACMhZ1J0"); } @Test @@ -89,21 +89,21 @@ public void testUrlWithNoAnalyticsNullAndTrue() { cloudinary.analytics.setSDKSemver("1.30.0"); cloudinary.analytics.setTechVersion("12.0.0"); String url = cloudinary.url().generate("test"); - Assert.assertEquals(url, "http://res.cloudinary.com/test123/image/upload/test?_a=AGAu5AM0"); + Assert.assertEquals(url, "http://res.cloudinary.com/test123/image/upload/test?_a=CAGAu5AMZAA0"); } @Test public void testMiscAnalyticsObject() { cloudinary.config.analytics = true; - Analytics analytics = new Analytics("Z", "1.24.0", "12.0.0"); + Analytics analytics = new Analytics("Z", "1.24.0", "12.0.0", "Z", "1.34.0"); String result = analytics.toQueryParam(); - Assert.assertEquals(result, "_a=AZAlhAM0"); + Assert.assertEquals(result, "_a=CAZAlhAMZ1J0"); } @Test public void testErrorAnalytics() { cloudinary.config.analytics = true; - Analytics analytics = new Analytics("Z", "1.24.0", "0"); + Analytics analytics = new Analytics("Z", "1.24.0", "0", "Z", "1.34.0"); String result = analytics.toQueryParam(); Assert.assertEquals(result, "_a=E"); } @@ -116,7 +116,7 @@ public void testUrlNoAnalyticsWithQueryParams() { cloudinary.config.cloudName = "test123"; cloudinary.config.analytics = true; - cloudinary.setAnalytics(new Analytics("F", "2.0.0", System.getProperty("java.version"))); + cloudinary.setAnalytics(new Analytics("F", "2.0.0", System.getProperty("java.version"), "Z", System.getProperty("os.version"))); cloudinary.config.privateCdn = true; String url = cloudinary.url().signed(true).type("authenticated").generate("test"); assertEquals(url,"http://test123-res.cloudinary.com/image/authenticated/test?__cld_token__=st=11111111~exp=11111411~hmac=735a49389a72ac0b90d1a84ac5d43facd1a9047f153b39e914747ef6ed195e53"); From 8688da17335b34dd97083e8edc82ec01e051bf92 Mon Sep 17 00:00:00 2001 From: adimiz1 Date: Wed, 11 Oct 2023 14:40:20 +0300 Subject: [PATCH 100/150] Version 1.35.0 --- CHANGELOG.md | 5 +++++ README.md | 4 ++-- cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java | 2 +- gradle.properties | 2 +- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c12c7b9..b17c3b36 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +1.35.0 / 2023-10-11 +=================== + + * Update analytics token + * Add support for `on_success` upload parameter 1.34.0 / 2023-08-08 =================== diff --git a/README.md b/README.md index 8f66ff78..82137d00 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ For the complete documentation, see the [Java SDK Guide](https://cloudinary.com/ ## Version Support | SDK Version | Java 6+ | |----------------|---------| -| 1.1.0 - 1.34.0 | V | +| 1.1.0 - 1.35.0 | V | ## Installation The cloudinary_java library is available in [Maven Central](https://mvnrepository.com/artifact/com.cloudinary/cloudinary-core). To use it, add the following dependency to your pom.xml : @@ -36,7 +36,7 @@ The cloudinary_java library is available in [Maven Central](https://mvnrepositor com.cloudinary cloudinary-http44 - 1.34.0 + 1.35.0 ``` diff --git a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java index 4ba99f40..1b945567 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java @@ -38,7 +38,7 @@ public class Cloudinary { public final static String AKAMAI_SHARED_CDN = "res.cloudinary.com"; public final static String SHARED_CDN = AKAMAI_SHARED_CDN; - public final static String VERSION = "1.34.0"; + public final static String VERSION = "1.35.0"; static String USER_AGENT_PREFIX = "CloudinaryJava"; public final static String USER_AGENT_JAVA_VERSION = "(Java " + System.getProperty("java.version") + ")"; diff --git a/gradle.properties b/gradle.properties index 7f41fc8c..9bd9f9d8 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,7 +13,7 @@ developerEmail=info@cloudinary.com # These two properties must use these exact names to be compatible with 'gradle install' plugin. group=com.cloudinary -version=1.34.0 +version=1.35.0 gnsp.disableApplyOnlyOnRootProjectEnforcement=true From 5566e593d0720d10675ced2b42f403d35f100ba0 Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Sun, 26 Nov 2023 14:12:43 +0200 Subject: [PATCH 101/150] Add support to use fetch format --- .../main/java/com/cloudinary/Configuration.java | 14 ++++++++++++++ .../src/main/java/com/cloudinary/Url.java | 9 ++++++++- .../java/com/cloudinary/test/CloudinaryTest.java | 7 +++++++ 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/cloudinary-core/src/main/java/com/cloudinary/Configuration.java b/cloudinary-core/src/main/java/com/cloudinary/Configuration.java index 9d3cc039..b0dcc41f 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Configuration.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Configuration.java @@ -40,6 +40,7 @@ public class Configuration { public Map properties = new HashMap(); public Boolean secureCdnSubdomain; public boolean useRootPath; + public boolean useFetchFormat; public int timeout; public boolean loadStrategies = true; public boolean clientHints = false; @@ -68,6 +69,7 @@ private Configuration( int proxyPort, Boolean secureCdnSubdomain, boolean useRootPath, + boolean useFetchFormat, int timeout, boolean loadStrategies, boolean forceVersion, @@ -90,6 +92,7 @@ private Configuration( this.proxyPort = proxyPort; this.secureCdnSubdomain = secureCdnSubdomain; this.useRootPath = useRootPath; + this.useFetchFormat = useFetchFormat; this.timeout = timeout; this.loadStrategies = loadStrategies; this.forceVersion = forceVersion; @@ -121,6 +124,7 @@ public void update(Map config) { this.proxyPort = ObjectUtils.asInteger(config.get("proxy_port"), 0); this.secureCdnSubdomain = ObjectUtils.asBoolean(config.get("secure_cdn_subdomain"), null); this.useRootPath = ObjectUtils.asBoolean(config.get("use_root_path"), false); + this.useFetchFormat = ObjectUtils.asBoolean(config.get("use_fetch_format"), false); this.loadStrategies = ObjectUtils.asBoolean(config.get("load_strategies"), true); this.timeout = ObjectUtils.asInteger(config.get("timeout"), 0); this.clientHints = ObjectUtils.asBoolean(config.get("client_hints"), false); @@ -158,6 +162,7 @@ public Map asMap() { map.put("proxy_port", proxyPort); map.put("secure_cdn_subdomain", secureCdnSubdomain); map.put("use_root_path", useRootPath); + map.put("use_fetch_format", useFetchFormat); map.put("load_strategies", loadStrategies); map.put("timeout", timeout); map.put("client_hints", clientHints); @@ -190,6 +195,7 @@ public Configuration(Configuration other) { this.proxyPort = other.proxyPort; this.secureCdnSubdomain = other.secureCdnSubdomain; this.useRootPath = other.useRootPath; + this.useFetchFormat = other.useFetchFormat; this.timeout = other.timeout; this.clientHints = other.clientHints; if (other.authToken != null) { @@ -306,6 +312,7 @@ public static class Builder { private int proxyPort; private Boolean secureCdnSubdomain; private boolean useRootPath; + private boolean useFetchFormat; private boolean loadStrategies = true; private int timeout; private boolean clientHints = false; @@ -347,6 +354,7 @@ public Configuration build() { proxyPort, secureCdnSubdomain, useRootPath, + useFetchFormat, timeout, loadStrategies, forceVersion, @@ -453,6 +461,11 @@ public Builder setUseRootPath(boolean useRootPath) { return this; } + public Builder setUseFetchFormat(boolean useFetchFormat) { + this.useFetchFormat = useFetchFormat; + return this; + } + public Builder setLoadStrategies(boolean loadStrategies) { this.loadStrategies = loadStrategies; return this; @@ -514,6 +527,7 @@ public Builder from(Configuration other) { this.proxyPort = other.proxyPort; this.secureCdnSubdomain = other.secureCdnSubdomain; this.useRootPath = other.useRootPath; + this.useFetchFormat = other.useFetchFormat; this.loadStrategies = other.loadStrategies; this.timeout = other.timeout; this.clientHints = other.clientHints; diff --git a/cloudinary-core/src/main/java/com/cloudinary/Url.java b/cloudinary-core/src/main/java/com/cloudinary/Url.java index a45382cd..6517bd28 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Url.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Url.java @@ -35,6 +35,7 @@ public class Url { String source = null; private String urlSuffix; private Boolean useRootPath; + private Boolean useFetchFormat; Map sourceTransformation = null; String[] sourceTypes = null; String fallbackContent = null; @@ -76,6 +77,7 @@ public Url clone() { cloned.sourceTypes = this.sourceTypes; cloned.urlSuffix = this.urlSuffix; cloned.useRootPath = this.useRootPath; + cloned.useFetchFormat = this.useFetchFormat; cloned.longUrlSignature = this.longUrlSignature; cloned.authToken = this.authToken; return cloned; @@ -172,6 +174,11 @@ public Url useRootPath(boolean useRootPath) { return this; } + public Url useFetchFormat(boolean useFetchFormat) { + this.useFetchFormat = useFetchFormat; + return this; + } + public Url cname(String cname) { this.config.cname = cname; return this; @@ -366,7 +373,7 @@ public String generate(String source) { } } - if (type != null && type.equals("fetch") && !StringUtils.isEmpty(format)) { + if ((type != null && type.equals("fetch") || (useFetchFormat != null && useFetchFormat)) && !StringUtils.isEmpty(format)) { transformation().fetchFormat(format); this.format = null; } diff --git a/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java b/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java index 8782dfc3..0b042bf9 100644 --- a/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java +++ b/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java @@ -492,6 +492,13 @@ public void testFetchFormat() { assertEquals("http://res.cloudinary.com/test123/image/fetch/f_jpg/http://cloudinary.com/images/old_logo.png", result); } + @Test + public void testUseFetchFormat() { + // should support use fetch format, adds the format but not an extension + String result = cloudinary.url().format("jpg").useFetchFormat(true).generate("old_logo"); + assertEquals("http://res.cloudinary.com/test123/image/upload/f_jpg/old_logo", result); + } + @Test public void testEffect() { // should support effect From 759b9e7725b18992c96dc10fbcb9b69e56b74904 Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Sun, 3 Dec 2023 07:25:29 +0200 Subject: [PATCH 102/150] Fix encode url for fetch layer --- .../main/java/com/cloudinary/transformation/FetchLayer.java | 2 +- .../src/test/java/com/cloudinary/test/CloudinaryTest.java | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/cloudinary-core/src/main/java/com/cloudinary/transformation/FetchLayer.java b/cloudinary-core/src/main/java/com/cloudinary/transformation/FetchLayer.java index 9c588a79..011a88e9 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/transformation/FetchLayer.java +++ b/cloudinary-core/src/main/java/com/cloudinary/transformation/FetchLayer.java @@ -9,7 +9,7 @@ public FetchLayer() { } public FetchLayer url(String remoteUrl) { - this.publicId = Base64Coder.encodeString(remoteUrl); + this.publicId = Base64Coder.encodeURLSafeString(remoteUrl);; return this; } diff --git a/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java b/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java index 0b042bf9..f23acd60 100644 --- a/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java +++ b/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java @@ -1266,7 +1266,10 @@ public void testOverlayOptions() { new FetchLayer().url("https://test"), "fetch:aHR0cHM6Ly90ZXN0", new FetchLayer().url("https://test").resourceType("video"), - "video:fetch:aHR0cHM6Ly90ZXN0"}; + "video:fetch:aHR0cHM6Ly90ZXN0", + new FetchLayer().url("https://www.test.com/test/JE01118-YGP900_1_lar.jpg?version=432023"), + "fetch:aHR0cHM6Ly93d3cudGVzdC5jb20vdGVzdC9KRTAxMTE4LVlHUDkwMF8xX2xhci5qcGc_dmVyc2lvbj00MzIwMjM=" + }; for (int i = 0; i < tests.length; i += 2) { Object layer = tests[i]; From f4fdd10967c57b680bd60a5c4dcc1c03ee74f7db Mon Sep 17 00:00:00 2001 From: adimiz1 Date: Mon, 4 Dec 2023 08:37:00 +0200 Subject: [PATCH 103/150] Version 1.36.0 --- CHANGELOG.md | 6 ++++++ README.md | 4 ++-- .../src/main/java/com/cloudinary/Cloudinary.java | 2 +- gradle.properties | 2 +- 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b17c3b36..dce59e1a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +1.36.0 / 2023-12-04 +=================== + +* Fix encode url for fetch layer +* Add support to use fetch format + 1.35.0 / 2023-10-11 =================== diff --git a/README.md b/README.md index 82137d00..c40b5901 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ For the complete documentation, see the [Java SDK Guide](https://cloudinary.com/ ## Version Support | SDK Version | Java 6+ | |----------------|---------| -| 1.1.0 - 1.35.0 | V | +| 1.1.0 - 1.36.0 | V | ## Installation The cloudinary_java library is available in [Maven Central](https://mvnrepository.com/artifact/com.cloudinary/cloudinary-core). To use it, add the following dependency to your pom.xml : @@ -36,7 +36,7 @@ The cloudinary_java library is available in [Maven Central](https://mvnrepositor com.cloudinary cloudinary-http44 - 1.35.0 + 1.36.0 ``` diff --git a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java index 1b945567..a35bdc2b 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java @@ -38,7 +38,7 @@ public class Cloudinary { public final static String AKAMAI_SHARED_CDN = "res.cloudinary.com"; public final static String SHARED_CDN = AKAMAI_SHARED_CDN; - public final static String VERSION = "1.35.0"; + public final static String VERSION = "1.36.0"; static String USER_AGENT_PREFIX = "CloudinaryJava"; public final static String USER_AGENT_JAVA_VERSION = "(Java " + System.getProperty("java.version") + ")"; diff --git a/gradle.properties b/gradle.properties index 9bd9f9d8..7050ae5f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,7 +13,7 @@ developerEmail=info@cloudinary.com # These two properties must use these exact names to be compatible with 'gradle install' plugin. group=com.cloudinary -version=1.35.0 +version=1.36.0 gnsp.disableApplyOnlyOnRootProjectEnforcement=true From cd2fc064ce98cbf54a2121da67c01621313886f1 Mon Sep 17 00:00:00 2001 From: Daniel Marcos Date: Tue, 9 Jan 2024 13:59:31 +0100 Subject: [PATCH 104/150] Add missing display_name parameter to update resource --- cloudinary-core/src/main/java/com/cloudinary/Util.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cloudinary-core/src/main/java/com/cloudinary/Util.java b/cloudinary-core/src/main/java/com/cloudinary/Util.java index 19ae2c71..99fa608c 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Util.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Util.java @@ -166,6 +166,9 @@ public static final void processWriteParameters(Map options, Map if (options.get("unique_display_name") != null) { params.put("unique_display_name", options.get("unique_display_name")); } + if (options.get("display_name") != null) { + params.put("display_name", options.get("display_name")); + } putObject("ocr", options, params); putObject("raw_convert", options, params); putObject("categorization", options, params); From 36039520710e4fef7ee6e148a95471d27e1c1953 Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Sun, 14 Jan 2024 09:15:58 +0200 Subject: [PATCH 105/150] Update analytics token --- .../java/com/cloudinary/utils/Analytics.java | 23 +++++++++++++++++-- .../cloudinary/analytics/AnalyticsTest.java | 20 +++++++++------- 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/cloudinary-core/src/main/java/com/cloudinary/utils/Analytics.java b/cloudinary-core/src/main/java/com/cloudinary/utils/Analytics.java index b0027889..d734377e 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/utils/Analytics.java +++ b/cloudinary-core/src/main/java/com/cloudinary/utils/Analytics.java @@ -8,7 +8,7 @@ public class Analytics { private String sdkTokenQueryKey = "_a"; //sdkTokenQueryKey private String sdkQueryDelimiter = "="; - public String algoVersion = "C"; + public String algoVersion = "D"; public String prodcut = "A"; public String SDKCode = ""; // Java = G, Android = F public String SDKSemver = ""; // Calculate the SDK version . @@ -67,12 +67,19 @@ private String versionArrayToString(String[] versions) throws Exception { return getPaddedString(StringUtils.join(versions, ".")); } + private String versionArrayToOsString(String[] versions) throws Exception { + if (versions.length > 2) { + versions = Arrays.copyOf(versions, versions.length - 1); + } + return getOsVersionString(StringUtils.join(versions, ".")); + } + private String getOsType() { return (osType != null) ? osType : "Z"; //System.getProperty("os.name"); } private String getOsVersion() throws Exception { - return (osVersion != null) ? versionArrayToString(osVersion.split("\\.")) : versionArrayToString(System.getProperty("os.version").split("\\.")); + return (osVersion != null) ? versionArrayToOsString(osVersion.split("\\.")) : versionArrayToString(System.getProperty("os.version").split("\\.")); } private String getSDKType() { @@ -91,6 +98,18 @@ private String getSDKVersion() throws Exception { return getPaddedString(SDKSemver); } + private String getOsVersionString(String string) throws Exception { + String[] parts = string.split("\\."); + String result = ""; + for(int i = 0 ; i < parts.length ; i++) { + int num = Integer.parseInt(parts[i]); + String binaryString = Integer.toBinaryString(num); + binaryString = StringUtils.padStart(binaryString, 6, '0'); + result = result + Base64Map.values.get(binaryString); + } + return result; + } + private String getPaddedString(String string) throws Exception { String paddedReversedSemver = ""; int parts = string.split("\\.").length; diff --git a/cloudinary-core/src/test/java/com/cloudinary/analytics/AnalyticsTest.java b/cloudinary-core/src/test/java/com/cloudinary/analytics/AnalyticsTest.java index fa277c15..7b4369a0 100644 --- a/cloudinary-core/src/test/java/com/cloudinary/analytics/AnalyticsTest.java +++ b/cloudinary-core/src/test/java/com/cloudinary/analytics/AnalyticsTest.java @@ -29,19 +29,19 @@ public void testEncodeVersion() { analytics.setSDKSemver("1.24.0"); analytics.setTechVersion("12.0.0"); String result = analytics.toQueryParam(); - Assert.assertEquals(result, "_a=CAGAlhAMZAA0"); + Assert.assertEquals(result, "_a=DAGAlhAMZAA0"); analytics.setSDKSemver("12.0"); result = analytics.toQueryParam(); - Assert.assertEquals(result, "_a=CAGAMAMZAA0"); + Assert.assertEquals(result, "_a=DAGAMAMZAA0"); analytics.setSDKSemver("43.21.26"); result = analytics.toQueryParam(); - Assert.assertEquals(result, "_a=CAG///AMZAA0"); + Assert.assertEquals(result, "_a=DAG///AMZAA0"); analytics.setSDKSemver("0.0.0"); result = analytics.toQueryParam(); - Assert.assertEquals(result, "_a=CAGAAAAMZAA0"); + Assert.assertEquals(result, "_a=DAGAAAAMZAA0"); analytics.setSDKSemver("43.21.27"); result = analytics.toQueryParam(); @@ -53,7 +53,11 @@ public void testEncodeVersion() { public void testToQueryParam() { Analytics analytics = new Analytics("F", "2.0.0", "1.8.0", "Z", "1.34.0"); String result = analytics.toQueryParam(); - Assert.assertEquals(result, "_a=CAFAACMhZ1J0"); + Assert.assertEquals(result, "_a=DAFAACMhZBi0"); + + analytics = new Analytics("F", "2.0.0", "1.8.0", "Z", "16.3"); + result = analytics.toQueryParam(); + Assert.assertEquals(result, "_a=DAFAACMhZQD0"); } @Test @@ -61,7 +65,7 @@ public void testUrlWithAnalytics() { cloudinary.config.analytics = true; cloudinary.setAnalytics(new Analytics("F", "2.0.0", "1.8.0", "Z", "1.34.0")); String url = cloudinary.url().generate("test"); - Assert.assertEquals(url, "http://res.cloudinary.com/test123/image/upload/test?_a=CAFAACMhZ1J0"); + Assert.assertEquals(url, "http://res.cloudinary.com/test123/image/upload/test?_a=DAFAACMhZBi0"); } @Test @@ -89,7 +93,7 @@ public void testUrlWithNoAnalyticsNullAndTrue() { cloudinary.analytics.setSDKSemver("1.30.0"); cloudinary.analytics.setTechVersion("12.0.0"); String url = cloudinary.url().generate("test"); - Assert.assertEquals(url, "http://res.cloudinary.com/test123/image/upload/test?_a=CAGAu5AMZAA0"); + Assert.assertEquals(url, "http://res.cloudinary.com/test123/image/upload/test?_a=DAGAu5AMZAA0"); } @Test @@ -97,7 +101,7 @@ public void testMiscAnalyticsObject() { cloudinary.config.analytics = true; Analytics analytics = new Analytics("Z", "1.24.0", "12.0.0", "Z", "1.34.0"); String result = analytics.toQueryParam(); - Assert.assertEquals(result, "_a=CAZAlhAMZ1J0"); + Assert.assertEquals(result, "_a=DAZAlhAMZBi0"); } @Test From c109e5e36a3e9cacf35bc8e6ee6eddaacb54b7cb Mon Sep 17 00:00:00 2001 From: adimiz1 Date: Sun, 14 Jan 2024 09:24:19 +0200 Subject: [PATCH 106/150] Version 1.37.0 --- CHANGELOG.md | 6 ++++++ README.md | 6 +++--- .../src/main/java/com/cloudinary/Cloudinary.java | 2 +- gradle.properties | 2 +- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dce59e1a..72a14fd8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +1.37.0 / 2024-01-14 +=================== + +* Update analytics token +* Add missing display name parameter + 1.36.0 / 2023-12-04 =================== diff --git a/README.md b/README.md index c40b5901..12989c75 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ For the complete documentation, see the [Java SDK Guide](https://cloudinary.com/ ## Version Support | SDK Version | Java 6+ | |----------------|---------| -| 1.1.0 - 1.36.0 | V | +| 1.1.0 - 1.37.0 | V | ## Installation The cloudinary_java library is available in [Maven Central](https://mvnrepository.com/artifact/com.cloudinary/cloudinary-core). To use it, add the following dependency to your pom.xml : @@ -35,8 +35,8 @@ The cloudinary_java library is available in [Maven Central](https://mvnrepositor ```xml com.cloudinary - cloudinary-http44 - 1.36.0 + cloudinary-http45 + 1.37.0 ``` diff --git a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java index a35bdc2b..3d1b7168 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java @@ -38,7 +38,7 @@ public class Cloudinary { public final static String AKAMAI_SHARED_CDN = "res.cloudinary.com"; public final static String SHARED_CDN = AKAMAI_SHARED_CDN; - public final static String VERSION = "1.36.0"; + public final static String VERSION = "1.37.0"; static String USER_AGENT_PREFIX = "CloudinaryJava"; public final static String USER_AGENT_JAVA_VERSION = "(Java " + System.getProperty("java.version") + ")"; diff --git a/gradle.properties b/gradle.properties index 7050ae5f..2202f4f5 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,7 +13,7 @@ developerEmail=info@cloudinary.com # These two properties must use these exact names to be compatible with 'gradle install' plugin. group=com.cloudinary -version=1.36.0 +version=1.37.0 gnsp.disableApplyOnlyOnRootProjectEnforcement=true From 0476ad62e14a0dc87ecf2c2636e3e7972c4fbac1 Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Thu, 15 Feb 2024 07:50:28 +0200 Subject: [PATCH 107/150] Add `notification_url` support to rename and destroy --- cloudinary-core/src/main/java/com/cloudinary/Uploader.java | 2 ++ .../java/com/cloudinary/test/AbstractUploaderTest.java | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/cloudinary-core/src/main/java/com/cloudinary/Uploader.java b/cloudinary-core/src/main/java/com/cloudinary/Uploader.java index e9a6909a..d2ae11ea 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Uploader.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Uploader.java @@ -234,6 +234,7 @@ public Map destroy(String publicId, Map options) throws IOException { params.put("type", (String) options.get("type")); params.put("public_id", publicId); params.put("invalidate", ObjectUtils.asBoolean(options.get("invalidate"), false).toString()); + params.put("notification_url", (String) options.get("notification_url")); return callApi("destroy", params, options, null); } @@ -249,6 +250,7 @@ public Map rename(String fromPublicId, String toPublicId, Map options) throws IO params.put("to_type", options.get("to_type")); params.put("context", ObjectUtils.asBoolean(options.get("context"), false).toString()); params.put("metadata", ObjectUtils.asBoolean(options.get("metadata"), false).toString()); + params.put("notification_url", (String) options.get("notification_url")); return callApi("rename", params, options, null); } diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java index bf590e13..1c12748b 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java @@ -831,4 +831,11 @@ public void testUploadFolderDecoupling() { Assert.assertEquals(true, uploadParams.get("use_asset_folder_as_public_id_prefix")); Assert.assertEquals(true, uploadParams.get("visual_search")); } + + @Test + public void testNotificationUrl() { + Map options = asMap("notification_url", "https://www.test.com"); + Map uploadParams = Util.buildUploadParams(options); + Assert.assertEquals("https://www.test.com", uploadParams.get("notification_url")); + } } From b4694e7d1f5d8cc7894e980eb0fcc924f9a772c7 Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Thu, 15 Feb 2024 15:52:02 +0200 Subject: [PATCH 108/150] Add analytics feature flag support --- .../java/com/cloudinary/utils/Analytics.java | 18 ++++++++++++----- .../cloudinary/analytics/AnalyticsTest.java | 20 +++++++++++++------ 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/cloudinary-core/src/main/java/com/cloudinary/utils/Analytics.java b/cloudinary-core/src/main/java/com/cloudinary/utils/Analytics.java index d734377e..55001eb2 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/utils/Analytics.java +++ b/cloudinary-core/src/main/java/com/cloudinary/utils/Analytics.java @@ -16,15 +16,18 @@ public class Analytics { public String osType; public String osVersion; + public String featureFlag = "0"; + public Analytics() { - this("G", Cloudinary.VERSION,System.getProperty("java.version"), "Z", "0.0"); + this("G", Cloudinary.VERSION,System.getProperty("java.version"), "Z", "0.0", "0"); } - public Analytics(String sdkCode, String sdkVersion, String techVersion, String osType, String osVersion) { + public Analytics(String sdkCode, String sdkVersion, String techVersion, String osType, String osVersion, String featureFlag) { this.SDKCode = sdkCode; this.SDKSemver = sdkVersion; this.techVersion = techVersion; this.osType = osType; this.osVersion = osVersion; + this.featureFlag = featureFlag; } public Analytics setSDKCode(String SDKCode) { @@ -42,13 +45,18 @@ public Analytics setTechVersion(String techVersion) { return this; } + public Analytics setFeatureFlag(String flag) { + this.featureFlag = flag; + return this; + } + /** * Function turn analytics variables into viable query parameter. * @return query param with analytics values. */ public String toQueryParam() { try { - return sdkTokenQueryKey + sdkQueryDelimiter + getAlgorithmVersion() + prodcut + getSDKType() + getSDKVersion() + getTechVersion() + getOsType() + getOsVersion() + getSDKFeatureCode(); + return sdkTokenQueryKey + sdkQueryDelimiter + getAlgorithmVersion() + prodcut + getSDKType() + getSDKVersion() + getTechVersion() + getOsType() + getOsVersion() + getSDKFeatureFlag(); } catch (Exception e) { return sdkTokenQueryKey + sdkQueryDelimiter + "E"; } @@ -90,8 +98,8 @@ private String getAlgorithmVersion() { return algoVersion; } - private String getSDKFeatureCode() { - return "0"; + private String getSDKFeatureFlag() { + return featureFlag; } private String getSDKVersion() throws Exception { diff --git a/cloudinary-core/src/test/java/com/cloudinary/analytics/AnalyticsTest.java b/cloudinary-core/src/test/java/com/cloudinary/analytics/AnalyticsTest.java index 7b4369a0..6300947e 100644 --- a/cloudinary-core/src/test/java/com/cloudinary/analytics/AnalyticsTest.java +++ b/cloudinary-core/src/test/java/com/cloudinary/analytics/AnalyticsTest.java @@ -51,11 +51,11 @@ public void testEncodeVersion() { @Test public void testToQueryParam() { - Analytics analytics = new Analytics("F", "2.0.0", "1.8.0", "Z", "1.34.0"); + Analytics analytics = new Analytics("F", "2.0.0", "1.8.0", "Z", "1.34.0", "0"); String result = analytics.toQueryParam(); Assert.assertEquals(result, "_a=DAFAACMhZBi0"); - analytics = new Analytics("F", "2.0.0", "1.8.0", "Z", "16.3"); + analytics = new Analytics("F", "2.0.0", "1.8.0", "Z", "16.3", "0"); result = analytics.toQueryParam(); Assert.assertEquals(result, "_a=DAFAACMhZQD0"); } @@ -63,7 +63,7 @@ public void testToQueryParam() { @Test public void testUrlWithAnalytics() { cloudinary.config.analytics = true; - cloudinary.setAnalytics(new Analytics("F", "2.0.0", "1.8.0", "Z", "1.34.0")); + cloudinary.setAnalytics(new Analytics("F", "2.0.0", "1.8.0", "Z", "1.34.0", "0")); String url = cloudinary.url().generate("test"); Assert.assertEquals(url, "http://res.cloudinary.com/test123/image/upload/test?_a=DAFAACMhZBi0"); } @@ -99,7 +99,7 @@ public void testUrlWithNoAnalyticsNullAndTrue() { @Test public void testMiscAnalyticsObject() { cloudinary.config.analytics = true; - Analytics analytics = new Analytics("Z", "1.24.0", "12.0.0", "Z", "1.34.0"); + Analytics analytics = new Analytics("Z", "1.24.0", "12.0.0", "Z", "1.34.0", "0"); String result = analytics.toQueryParam(); Assert.assertEquals(result, "_a=DAZAlhAMZBi0"); } @@ -107,7 +107,7 @@ public void testMiscAnalyticsObject() { @Test public void testErrorAnalytics() { cloudinary.config.analytics = true; - Analytics analytics = new Analytics("Z", "1.24.0", "0", "Z", "1.34.0"); + Analytics analytics = new Analytics("Z", "1.24.0", "0", "Z", "1.34.0", "0"); String result = analytics.toQueryParam(); Assert.assertEquals(result, "_a=E"); } @@ -120,13 +120,21 @@ public void testUrlNoAnalyticsWithQueryParams() { cloudinary.config.cloudName = "test123"; cloudinary.config.analytics = true; - cloudinary.setAnalytics(new Analytics("F", "2.0.0", System.getProperty("java.version"), "Z", System.getProperty("os.version"))); + cloudinary.setAnalytics(new Analytics("F", "2.0.0", System.getProperty("java.version"), "Z", System.getProperty("os.version"), "0")); cloudinary.config.privateCdn = true; String url = cloudinary.url().signed(true).type("authenticated").generate("test"); assertEquals(url,"http://test123-res.cloudinary.com/image/authenticated/test?__cld_token__=st=11111111~exp=11111411~hmac=735a49389a72ac0b90d1a84ac5d43facd1a9047f153b39e914747ef6ed195e53"); cloudinary.config.privateCdn = false; } + @Test + public void testFeatureFlag() { + Analytics analytics = new Analytics("F", "2.0.0", "1.8.0", "Z", "1.34.0", "0"); + analytics.setFeatureFlag("F"); + String result = analytics.toQueryParam(); + Assert.assertEquals(result, "_a=DAFAACMhZBiF"); + } + @After public void tearDown() { cloudinary.config.analytics = false; From c1abb9169c1a5e5b58932db314e45fd436a7f9bf Mon Sep 17 00:00:00 2001 From: adimiz1 Date: Sun, 18 Feb 2024 08:22:05 +0200 Subject: [PATCH 109/150] Version 1.38.0 --- CHANGELOG.md | 5 +++++ README.md | 4 ++-- cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java | 2 +- gradle.properties | 2 +- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 72a14fd8..0a520f7d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +1.38.0 / 2024-02-18 +=================== + +* Add `notification_url` support to rename and destroy + 1.37.0 / 2024-01-14 =================== diff --git a/README.md b/README.md index 12989c75..b4eb9244 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ For the complete documentation, see the [Java SDK Guide](https://cloudinary.com/ ## Version Support | SDK Version | Java 6+ | |----------------|---------| -| 1.1.0 - 1.37.0 | V | +| 1.1.0 - 1.38.0 | V | ## Installation The cloudinary_java library is available in [Maven Central](https://mvnrepository.com/artifact/com.cloudinary/cloudinary-core). To use it, add the following dependency to your pom.xml : @@ -36,7 +36,7 @@ The cloudinary_java library is available in [Maven Central](https://mvnrepositor com.cloudinary cloudinary-http45 - 1.37.0 + 1.38.0 ``` diff --git a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java index 3d1b7168..af553631 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java @@ -38,7 +38,7 @@ public class Cloudinary { public final static String AKAMAI_SHARED_CDN = "res.cloudinary.com"; public final static String SHARED_CDN = AKAMAI_SHARED_CDN; - public final static String VERSION = "1.37.0"; + public final static String VERSION = "1.38.0"; static String USER_AGENT_PREFIX = "CloudinaryJava"; public final static String USER_AGENT_JAVA_VERSION = "(Java " + System.getProperty("java.version") + ")"; diff --git a/gradle.properties b/gradle.properties index 2202f4f5..b3933bac 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,7 +13,7 @@ developerEmail=info@cloudinary.com # These two properties must use these exact names to be compatible with 'gradle install' plugin. group=com.cloudinary -version=1.37.0 +version=1.38.0 gnsp.disableApplyOnlyOnRootProjectEnforcement=true From 923594a12484bc86279d6d05f488093a1e12a499 Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Wed, 6 Mar 2024 13:04:20 +0200 Subject: [PATCH 110/150] Add restrictions field to metadata (#312) --- .../cloudinary/metadata/MetadataField.java | 9 +++++ .../com/cloudinary/metadata/Restrictions.java | 40 +++++++++++++++++++ .../test/AbstractStructuredMetadataTest.java | 24 +++++++++-- 3 files changed, 69 insertions(+), 4 deletions(-) create mode 100644 cloudinary-core/src/main/java/com/cloudinary/metadata/Restrictions.java diff --git a/cloudinary-core/src/main/java/com/cloudinary/metadata/MetadataField.java b/cloudinary-core/src/main/java/com/cloudinary/metadata/MetadataField.java index bae2b6c7..7dee301f 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/metadata/MetadataField.java +++ b/cloudinary-core/src/main/java/com/cloudinary/metadata/MetadataField.java @@ -16,6 +16,7 @@ public class MetadataField extends JSONObject { public static final String MANDATORY = "mandatory"; public static final String TYPE = "type"; public static final String VALIDATION = "validation"; + public static final String RESTRICTIONS = "restrictions"; public MetadataField(MetadataFieldType type) { put(TYPE, type.toString()); @@ -130,4 +131,12 @@ public MetadataDataSource getDataSource() { public void setDataSource(MetadataDataSource dataSource) { put("datasource", dataSource); } + + /** + * Set the restrictions rules of this field. + * @param restrictions The rules to set. + */ + public void setRestrictions(Restrictions restrictions) { + put(RESTRICTIONS, restrictions.toHash()); + } } \ No newline at end of file diff --git a/cloudinary-core/src/main/java/com/cloudinary/metadata/Restrictions.java b/cloudinary-core/src/main/java/com/cloudinary/metadata/Restrictions.java new file mode 100644 index 00000000..25d80d12 --- /dev/null +++ b/cloudinary-core/src/main/java/com/cloudinary/metadata/Restrictions.java @@ -0,0 +1,40 @@ +package com.cloudinary.metadata; + +import java.util.HashMap; + +/** + * Represents the restrictions metadata field. + */ +public class Restrictions { + + private final HashMap restrictions = new HashMap(); + + /** + * Set the custom field into restrictions. + * @param key The key of the field. + * @param value The value of the field. + */ + public Restrictions setRestriction(String key, Object value) { + restrictions.put(key, value); + return this; + } + + /** + * Set the read only ui field. + * @param value The read only ui value. + */ + public Restrictions setReadOnlyUI(Boolean value) { + return setRestriction("readonly_ui", value); + } + + /** + * Set the read only ui field to true. + */ + public Restrictions setReadOnlyUI() { + return this.setReadOnlyUI(true); + } + + public HashMap toHash() { + return restrictions; + } +} diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractStructuredMetadataTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractStructuredMetadataTest.java index b6e541a7..bb8f1b9b 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractStructuredMetadataTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractStructuredMetadataTest.java @@ -72,6 +72,18 @@ public void testCreateMetadata() throws Exception { assertEquals(setField.getLabel(), result.get("label")); } + @Test + public void testFieldRestrictions() throws Exception { + StringMetadataField stringField = newFieldInstance("testCreateMetadata_3"); + stringField.setRestrictions(new Restrictions().setReadOnlyUI()); + + ApiResponse result = api.addMetadataField(stringField); + assertNotNull(result); + Map restrictions = (Map) result.get("restrictions"); + assertNotNull(restrictions); + assertTrue((Boolean) restrictions.get("readonly_ui")); + } + @Test public void testDateFieldDefaultValueValidation() throws Exception { // now minus 3 days hours. @@ -130,13 +142,17 @@ public void testGetMetadata() throws Exception { @Test public void testUpdateField() throws Exception { - ApiResponse fieldResult = addFieldToAccount(newFieldInstance("testUpdateField")); + StringMetadataField metadataField = newFieldInstance("testUpdateField"); + ApiResponse fieldResult = addFieldToAccount(metadataField); assertNotEquals("new_def", fieldResult.get("default_value")); - StringMetadataField field = new StringMetadataField(); - field.setDefaultValue("new_def"); - ApiResponse result = api.updateMetadataField(fieldResult.get("external_id").toString(), field); + metadataField.setDefaultValue("new_def"); + metadataField.setRestrictions(new Restrictions().setReadOnlyUI()); + ApiResponse result = api.updateMetadataField(fieldResult.get("external_id").toString(), metadataField); assertNotNull(result); assertEquals("new_def", result.get("default_value")); + Map restrictions = (Map) result.get("restrictions"); + assertNotNull(restrictions); + assertTrue((Boolean)restrictions.get("readonly_ui")); } @Test From 09e0719c7750233890f0c75026dab10828363a4b Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Wed, 6 Mar 2024 14:17:28 +0200 Subject: [PATCH 111/150] Add access key management --- .../com/cloudinary/provisioning/Account.java | 56 +++++++++++++++++++ .../test/AbstractAccountApiTest.java | 41 ++++++++++++++ 2 files changed, 97 insertions(+) diff --git a/cloudinary-core/src/main/java/com/cloudinary/provisioning/Account.java b/cloudinary-core/src/main/java/com/cloudinary/provisioning/Account.java index 55860aa5..c149e5dc 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/provisioning/Account.java +++ b/cloudinary-core/src/main/java/com/cloudinary/provisioning/Account.java @@ -14,8 +14,10 @@ public class Account { private static final String CLOUDINARY_ACCOUNT_URL = "CLOUDINARY_ACCOUNT_URL"; public static final String PROVISIONING = "provisioning"; public static final String ACCOUNTS = "accounts"; + public static final String SUB_ACCOUNTS = "sub_accounts"; public static final String USERS = "users"; public static final String USER_GROUPS = "user_groups"; + public static final String ACCESS_KEYS = "access_keys"; private final AccountConfiguration configuration; private final String accountId; @@ -619,6 +621,60 @@ public ApiResponse userGroupUsers(String groupId, Map options) t return callAccountApi(Api.HttpMethod.GET, uri, Collections.emptyMap(), options); } + /** + * Lists the access keys belonging to this sub account id. + * @param subAccountId The id of the user group. + * @param options Generic advanced options map, see online documentation. + * @return The list of access keys in that sub account id. + * @throws Exception If the request fails. + */ + public ApiResponse getAccessKeys(String subAccountId, Map options) throws Exception { + List uri = Arrays.asList(PROVISIONING, ACCOUNTS, accountId, SUB_ACCOUNTS, subAccountId); + return callAccountApi(Api.HttpMethod.GET, uri, Collections.emptyMap(), options); + } + + /** + * Creates a new access key for this sub account id. + * @param subAccountId The id of the user group. + * @param name The name for the access key. + * @param enabled Access key's status (enabled or disabled). + * @param options Generic advanced options map, see online documentation. + * @return The created access key. + * @throws Exception If the request fails. + */ + public ApiResponse createAccessKey(String subAccountId, String name, Boolean enabled, Map options) throws Exception { + List uri = Arrays.asList(PROVISIONING, ACCOUNTS, accountId, SUB_ACCOUNTS, subAccountId, ACCESS_KEYS); + return callAccountApi(Api.HttpMethod.POST, uri, ObjectUtils.asMap("name", name, "enabled", enabled), options); + } + + /** + * Updates an existing access key for this sub account id. + * @param subAccountId The id of the user group. + * @param accessKey The key of the access key. + * @param name The name for the access key. + * @param enabled Access key's status (enabled or disabled). + * @param options Generic advanced options map, see online documentation. + * @return The updated access key. + * @throws Exception If the request fails. + */ + public ApiResponse updateAccessKey(String subAccountId, String accessKey, String name, Boolean enabled, Map options) throws Exception { + List uri = Arrays.asList(PROVISIONING, ACCOUNTS, accountId, SUB_ACCOUNTS, subAccountId, ACCESS_KEYS, accessKey); + return callAccountApi(Api.HttpMethod.PUT, uri, ObjectUtils.asMap("name", name, "enabled", enabled), options); + } + + /** + * Deletes an existing access key for this sub account id. + * @param subAccountId The id of the user group. + * @param accessKey The key of the access key. + * @param options Generic advanced options map, see online documentation. + * @return "message": "ok". + * @throws Exception If the request fails. + */ + public ApiResponse deleteAccessKey(String subAccountId, String accessKey, Map options) throws Exception { + List uri = Arrays.asList(PROVISIONING, ACCOUNTS, accountId, SUB_ACCOUNTS, subAccountId, ACCESS_KEYS, accessKey); + return callAccountApi(Api.HttpMethod.DELETE, uri, Collections.emptyMap(), options); + } + /** * Private helper method for users api calls * @param method Http method diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractAccountApiTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractAccountApiTest.java index 7513907a..5b8e9633 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractAccountApiTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractAccountApiTest.java @@ -423,6 +423,47 @@ public void testListUsersInGroup() throws Exception { deleteUser(user2Id); } + @Test + public void testGetAccessKeys() throws Exception { + ApiResponse createResult = createSubAccount(); + ApiResponse result = account.getAccessKeys((String) createResult.get("id"), ObjectUtils.emptyMap()); + assertNotNull(result); + } + + @Test + public void testCreateNewAccessKey() throws Exception { + ApiResponse createResult = createSubAccount(); + String name = randomLetters(); + ApiResponse result = account.createAccessKey((String)createResult.get("id"), name, true, ObjectUtils.emptyMap()); + assertNotNull(result); + assertTrue((Boolean) result.get("enabled")); + } + + @Test + public void testUpdateAccessKey() throws Exception { + ApiResponse createResult = createSubAccount(); + String name = randomLetters(); + ApiResponse result = account.createAccessKey((String)createResult.get("id"), name, false, ObjectUtils.emptyMap()); + assertNotNull(result); + + String updatedName = randomLetters(); + result = account.updateAccessKey((String)createResult.get("id"), (String) result.get("api_key"), updatedName, true, ObjectUtils.emptyMap()); + assertNotNull(result); + assertEquals(updatedName, result.get("name")); + assertTrue((Boolean) result.get("enabled")); + } + + @Test + public void testDeleteAccessKey() throws Exception { + ApiResponse createResult = createSubAccount(); + String name = randomLetters(); + ApiResponse result = account.createAccessKey((String)createResult.get("id"), name, false, ObjectUtils.emptyMap()); + assertNotNull(result); + + result = account.deleteAccessKey((String)createResult.get("id"), (String) result.get("api_key"), ObjectUtils.emptyMap()); + assertNotNull(result); + } + // Helpers private ApiResponse createGroup() throws Exception { From 959f98acd45da23f941c88f04a600271166ce1db Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Wed, 13 Mar 2024 13:08:16 +0200 Subject: [PATCH 112/150] Add selective response support --- .../src/main/java/com/cloudinary/Api.java | 33 ++++++++++++++----- .../src/main/java/com/cloudinary/Search.java | 12 +++++++ .../com/cloudinary/test/AbstractApiTest.java | 27 +++++++++++++++ .../cloudinary/test/AbstractSearchTest.java | 12 +++++++ 4 files changed, 75 insertions(+), 9 deletions(-) diff --git a/cloudinary-core/src/main/java/com/cloudinary/Api.java b/cloudinary-core/src/main/java/com/cloudinary/Api.java index 828b821b..24df4a05 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Api.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Api.java @@ -87,8 +87,10 @@ public ApiResponse resources(Map options) throws Exception { uri.add(resourceType); if (type != null) uri.add(type); - - ApiResponse response = callApi(HttpMethod.GET, uri, ObjectUtils.only(options, "next_cursor", "direction", "max_results", "prefix", "tags", "context", "moderations", "start_at", "metadata"), options); + if(options.get("fields") != null) { + options.put("fields", StringUtils.join(ObjectUtils.asArray(options.get("fields")), ",")); + } + ApiResponse response = callApi(HttpMethod.GET, uri, ObjectUtils.only(options, "next_cursor", "direction", "max_results", "prefix", "tags", "context", "moderations", "start_at", "metadata", "fields"), options); return response; } @@ -106,8 +108,10 @@ public ApiResponse visualSearch(Map options) throws Exception { public ApiResponse resourcesByTag(String tag, Map options) throws Exception { if (options == null) options = ObjectUtils.emptyMap(); String resourceType = ObjectUtils.asString(options.get("resource_type"), "image"); - - ApiResponse response = callApi(HttpMethod.GET, Arrays.asList("resources", resourceType, "tags", tag), ObjectUtils.only(options, "next_cursor", "direction", "max_results", "tags", "context", "moderations", "metadata"), options); + if(options.get("fields") != null) { + options.put("fields", StringUtils.join(ObjectUtils.asArray(options.get("fields")), ",")); + } + ApiResponse response = callApi(HttpMethod.GET, Arrays.asList("resources", resourceType, "tags", tag), ObjectUtils.only(options, "next_cursor", "direction", "max_results", "tags", "context", "moderations", "metadata", "fields"), options); return response; } @@ -118,7 +122,10 @@ public ApiResponse resourcesByContext(String key, 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", "metadata"); + if(options.get("fields") != null) { + options.put("fields", StringUtils.join(ObjectUtils.asArray(options.get("fields")), ",")); + } + Map params = ObjectUtils.only(options, "next_cursor", "direction", "max_results", "tags", "context", "moderations", "metadata", "fields"); params.put("key", key); if (StringUtils.isNotBlank(value)) { params.put("value", value); @@ -128,7 +135,10 @@ public ApiResponse resourcesByContext(String key, String value, Map options) thr public ApiResponse resourceByAssetID(String assetId, Map options) throws Exception { if (options == null) options = ObjectUtils.emptyMap(); - Map params = ObjectUtils.only(options, "tags", "context", "moderations"); + if(options.get("fields") != null) { + options.put("fields", StringUtils.join(ObjectUtils.asArray(options.get("fields")), ",")); + } + Map params = ObjectUtils.only(options, "tags", "context", "moderations", "fields"); ApiResponse response = callApi(HttpMethod.GET, Arrays.asList("resources", assetId), params, options); return response; } @@ -142,7 +152,10 @@ public ApiResponse resourcesByAssetIDs(Iterable assetIds, Map options) t public ApiResponse resourcesByAssetFolder(String assetFolder, Map options) throws Exception { if (options == null) options = ObjectUtils.emptyMap(); - Map params = ObjectUtils.only(options, "next_cursor", "direction", "max_results", "tags", "context", "moderations"); + if(options.get("fields") != null) { + options.put("fields", StringUtils.join(ObjectUtils.asArray(options.get("fields")), ",")); + } + Map params = ObjectUtils.only(options, "next_cursor", "direction", "max_results", "tags", "context", "moderations", "fields"); params.put("asset_folder", assetFolder); ApiResponse response = callApi(HttpMethod.GET, Arrays.asList("resources/by_asset_folder"), params, options); return response; @@ -161,8 +174,10 @@ public ApiResponse resourcesByIds(Iterable publicIds, Map options) throw public ApiResponse resourcesByModeration(String kind, String status, Map options) throws Exception { if (options == null) options = ObjectUtils.emptyMap(); String resourceType = ObjectUtils.asString(options.get("resource_type"), "image"); - - ApiResponse response = callApi(HttpMethod.GET, Arrays.asList("resources", resourceType, "moderations", kind, status), ObjectUtils.only(options, "next_cursor", "direction", "max_results", "tags", "context", "moderations", "metadata"), options); + if(options.get("fields") != null) { + options.put("fields", StringUtils.join(ObjectUtils.asArray(options.get("fields")), ",")); + } + ApiResponse response = callApi(HttpMethod.GET, Arrays.asList("resources", resourceType, "moderations", kind, status), ObjectUtils.only(options, "next_cursor", "direction", "max_results", "tags", "context", "moderations", "metadata", "fields"), options); return response; } diff --git a/cloudinary-core/src/main/java/com/cloudinary/Search.java b/cloudinary-core/src/main/java/com/cloudinary/Search.java index 652e2cda..2ba3ac8b 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Search.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Search.java @@ -19,6 +19,7 @@ public class Search { private ArrayList aggregateParam; private ArrayList withFieldParam; private HashMap params; + private ArrayList fields; private int ttl = 300; @@ -28,6 +29,7 @@ public class Search { this.sortByParam = new ArrayList>(); this.aggregateParam = new ArrayList(); this.withFieldParam = new ArrayList(); + this.fields = new ArrayList(); } public Search ttl(int ttl) { @@ -76,6 +78,13 @@ public Search sortBy(String field, String dir) { return this; } + public Search fields(String field) { + if (!fields.contains(field)) { + fields.add(field); + } + return this; + } + public HashMap toQuery() { HashMap queryParams = new HashMap(this.params); if (withFieldParam.size() > 0) { @@ -87,6 +96,9 @@ public HashMap toQuery() { if(aggregateParam.size() > 0) { queryParams.put("aggregate", aggregateParam); } + if(fields.size() > 0) { + queryParams.put("fields", fields); + } return queryParams; } diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java index 24cc490d..141b1ff3 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java @@ -181,6 +181,33 @@ public void test01ResourceTypes() throws Exception { assertThat(resource_types, hasItem("image")); } + @Test + public void testSingleSelectiveResponse() throws Exception { + Map options = new HashMap(); + options.put("fields", "width"); + Map result = api.resources(options); + List resources = (List) result.get("resources"); + assertNotNull(resources); + Map resource = resources.get(0); + assertNotNull(resource); + assertNotNull(resource.get("width")); + assertNull(resource.get("format")); + } + + @Test + public void testMultipleSelectiveResponse() throws Exception { + Map options = new HashMap(); + options.put("fields", new String[]{"width", "format"}); + Map result = api.resources(options); + List resources = (List) result.get("resources"); + assertNotNull(resources); + Map resource = resources.get(0); + assertNotNull(resource); + assertNotNull(resource.get("width")); + assertNotNull(resource.get("format")); + assertNull(resource.get("height")); + } + @Test public void test03ResourcesCursor() throws Exception { // should allow listing resources with cursor diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractSearchTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractSearchTest.java index 1d0a2094..5e30d26b 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractSearchTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractSearchTest.java @@ -177,4 +177,16 @@ public void testShouldBuildSearchUrl() throws Exception { cloudinaryToSearch.config.privateCdn = true; assertEquals(String.format("https://%s-res.cloudinary.com/search/%s/%d/%s", cloudinaryToSearch.config.cloudName, ttl300Signature, 300, base64Query), search.toUrl(300, "")); } + + @Test + public void testSearchWithSelectiveResponse() throws Exception { + Map result = cloudinary.search().expression(String.format("tags:%s", SEARCH_TAG)).fields("width").fields("height").execute(); + List resources = (List) result.get("resources"); + assertEquals(3, resources.size()); + Map resource = resources.get(0); + assertNotNull(resource); + assertNotNull(resource.get("width")); + assertNotNull(resource.get("height")); + assertNull(resource.get("format")); + } } \ No newline at end of file From 36d721803f6332b07a35cb12c355f05f85435cef Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Thu, 14 Mar 2024 15:37:22 +0200 Subject: [PATCH 113/150] Add analyze api --- cloudinary-core/src/main/java/com/cloudinary/Api.java | 11 +++++++++++ .../cloudinary/strategies/AbstractApiStrategy.java | 10 +++++++--- .../main/java/com/cloudinary/http42/ApiStrategy.java | 5 +---- .../main/java/com/cloudinary/http43/ApiStrategy.java | 5 +---- .../main/java/com/cloudinary/http44/ApiStrategy.java | 5 +---- .../main/java/com/cloudinary/http45/ApiStrategy.java | 6 +----- .../java/com/cloudinary/test/AbstractApiTest.java | 8 ++++++++ 7 files changed, 30 insertions(+), 20 deletions(-) diff --git a/cloudinary-core/src/main/java/com/cloudinary/Api.java b/cloudinary-core/src/main/java/com/cloudinary/Api.java index 24df4a05..f97ed09e 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Api.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Api.java @@ -779,6 +779,17 @@ public ApiResponse reorderMetadataFields(String orderBy, String direction, Map o return callApi(HttpMethod.PUT, uri, map, options); } + public ApiResponse analyze(String inputType, String analysisType, String uri, Map options) throws Exception { + if (options == null || options.isEmpty()) options = ObjectUtils.asMap(); + List url = Arrays.asList("analysis", "analyze", inputType); + options.put("api_version", "v2"); + options.put("content_type", "json"); + final Map params = new HashMap(); + params.put("analysis_type", analysisType); + params.put("uri", uri); + return callApi(HttpMethod.POST, url, params, options); + } + private Map extractParams(Map options, List keys) { Map result = new HashMap(); for (String key : keys) { diff --git a/cloudinary-core/src/main/java/com/cloudinary/strategies/AbstractApiStrategy.java b/cloudinary-core/src/main/java/com/cloudinary/strategies/AbstractApiStrategy.java index 9e427c4a..2d5a514d 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/strategies/AbstractApiStrategy.java +++ b/cloudinary-core/src/main/java/com/cloudinary/strategies/AbstractApiStrategy.java @@ -5,6 +5,7 @@ import com.cloudinary.SmartUrlEncoder; import com.cloudinary.api.ApiResponse; import com.cloudinary.utils.Base64Coder; +import com.cloudinary.utils.ObjectUtils; import com.cloudinary.utils.StringUtils; import java.util.Arrays; import java.util.Map; @@ -17,9 +18,12 @@ public void init(Api api) { this.api = api; } - protected String createApiUrl (Iterable uri, String prefix, String cloudName){ - - String apiUrl = StringUtils.join(Arrays.asList(prefix, "v1_1", cloudName), "/"); + protected String createApiUrl (Iterable uri, Map options){ + String version = ObjectUtils.asString(options.get("api_version"), "v1_1"); + String prefix = ObjectUtils.asString(options.get("upload_prefix"), ObjectUtils.asString(this.api.cloudinary.config.uploadPrefix, "https://api.cloudinary.com")); + String cloudName = ObjectUtils.asString(options.get("cloud_name"), this.api.cloudinary.config.cloudName); + if (cloudName == null) throw new IllegalArgumentException("Must supply cloud_name"); + String apiUrl = StringUtils.join(Arrays.asList(prefix, version, cloudName), "/"); for (String component : uri) { component = SmartUrlEncoder.encode(component); apiUrl = apiUrl + "/" + component; diff --git a/cloudinary-http42/src/main/java/com/cloudinary/http42/ApiStrategy.java b/cloudinary-http42/src/main/java/com/cloudinary/http42/ApiStrategy.java index 6703448e..4a90ed86 100644 --- a/cloudinary-http42/src/main/java/com/cloudinary/http42/ApiStrategy.java +++ b/cloudinary-http42/src/main/java/com/cloudinary/http42/ApiStrategy.java @@ -34,9 +34,6 @@ public class ApiStrategy extends AbstractApiStrategy { public ApiResponse callApi(HttpMethod method, Iterable uri, Map params, Map options) throws Exception { if (options == null) options = ObjectUtils.emptyMap(); - String prefix = ObjectUtils.asString(options.get("upload_prefix"), ObjectUtils.asString(this.api.cloudinary.config.uploadPrefix, "https://api.cloudinary.com")); - String cloudName = ObjectUtils.asString(options.get("cloud_name"), this.api.cloudinary.config.cloudName); - if (cloudName == null) throw new IllegalArgumentException("Must supply cloud_name"); String apiKey = ObjectUtils.asString(options.get("api_key"), this.api.cloudinary.config.apiKey); String apiSecret = ObjectUtils.asString(options.get("api_secret"), this.api.cloudinary.config.apiSecret); String oauthToken = ObjectUtils.asString(options.get("oauth_token"), this.api.cloudinary.config.oauthToken); @@ -44,7 +41,7 @@ public ApiResponse callApi(HttpMethod method, Iterable uri, Map uri, Map uri, Map uri, Map Date: Thu, 28 Mar 2024 10:54:32 +0200 Subject: [PATCH 114/150] Add filename test to upload large --- .../main/java/com/cloudinary/test/AbstractUploaderTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java index 1c12748b..bddf48cc 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java @@ -571,11 +571,12 @@ public void testUploadLarge() throws Exception { assertEquals("raw", resource.get("resource_type")); assertTrue(resource.get("public_id").toString().startsWith("cldupload")); - resource = cloudinary.uploader().uploadLarge(new FileInputStream(temp), asMap("chunk_size", 5243000, "tags", tags)); + resource = cloudinary.uploader().uploadLarge(new FileInputStream(temp), asMap("filename", "test123", "chunk_size", 5243000, "tags", tags)); assertArrayEquals(tags, ((java.util.ArrayList) resource.get("tags")).toArray()); assertEquals("image", resource.get("resource_type")); assertEquals(1400, resource.get("width")); assertEquals(1400, resource.get("height")); + assertEquals("test123", resource.get("original_filename")); resource = cloudinary.uploader().uploadLarge(temp, asMap("chunk_size", 5880138, "tags", tags)); assertArrayEquals(tags, ((java.util.ArrayList) resource.get("tags")).toArray()); From 40941ecb3485c3fcd530293df20508e1fe229618 Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Tue, 30 Apr 2024 07:19:28 +0300 Subject: [PATCH 115/150] Add rename folder api support --- .../src/main/java/com/cloudinary/Api.java | 12 ++++++++++++ .../java/com/cloudinary/test/AbstractApiTest.java | 11 +++++++++++ 2 files changed, 23 insertions(+) diff --git a/cloudinary-core/src/main/java/com/cloudinary/Api.java b/cloudinary-core/src/main/java/com/cloudinary/Api.java index f97ed09e..c9b59d0e 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Api.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Api.java @@ -790,6 +790,18 @@ public ApiResponse analyze(String inputType, String analysisType, String uri, Ma return callApi(HttpMethod.POST, url, params, options); } + public ApiResponse renameFolder(String path, String toPath, Map options) throws Exception { + if (options == null || options.isEmpty()) options = ObjectUtils.asMap(); + List url = Arrays.asList("folder_operations", "rename"); + + final Map params = new HashMap(); + params.put("path", path); + params.put("to_path", toPath); + + return callApi(HttpMethod.PUT, url, params, options); + + } + private Map extractParams(Map options, List keys) { Map result = new HashMap(); for (String key : keys) { diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java index 15bbf17c..889b15f6 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java @@ -1267,4 +1267,15 @@ public void testVisualSearch() { Util.processWriteParameters(options, params); assertEquals(true, params.get("visual_search")); } + + @Test + @Ignore("Skip test till FD is enabled for test accounts") + public void testRenameFolder() throws Exception { + Map result = api.createFolder("apTestCreateFolder", null); + assertNotNull(result); + + String folderName = (String) result.get("path"); + Map response = api.renameFolder(folderName, "newFolderName", ObjectUtils.emptyMap()); + assertNotNull(response); + } } From bd829089b00690a694838fea30a99ab7cf55ae69 Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Sun, 5 May 2024 08:20:15 +0300 Subject: [PATCH 116/150] Add delete backup asset version support --- .../src/main/java/com/cloudinary/Api.java | 19 ++++++++++++++++++ .../com/cloudinary/test/AbstractApiTest.java | 20 +++++++++++++++++++ .../com/cloudinary/test/helpers/Feature.java | 1 + 3 files changed, 40 insertions(+) diff --git a/cloudinary-core/src/main/java/com/cloudinary/Api.java b/cloudinary-core/src/main/java/com/cloudinary/Api.java index c9b59d0e..daaa30df 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Api.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Api.java @@ -802,6 +802,25 @@ public ApiResponse renameFolder(String path, String toPath, Map options) throws } + public ApiResponse deleteBackedUpAssets(String assetId, String[] versionIds, Map options) throws Exception { + if (options == null || options.isEmpty()) options = ObjectUtils.asMap(); + if (StringUtils.isEmpty(assetId)) { + throw new IllegalArgumentException("AssetId parameter is required"); + } + + if (versionIds == null || versionIds.length == 0) { + throw new IllegalArgumentException("VersionIds parameter is required"); + } + + List url = Arrays.asList("resources", "backup", assetId); + + Map params = new HashMap(); + params.put("version_ids[]", StringUtils.join(versionIds, "&")); + + return callApi(HttpMethod.DELETE, url, params, options); + + } + private Map extractParams(Map options, List keys) { Map result = new HashMap(); for (String key : keys) { diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java index 889b15f6..7ffd138e 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java @@ -1278,4 +1278,24 @@ public void testRenameFolder() throws Exception { Map response = api.renameFolder(folderName, "newFolderName", ObjectUtils.emptyMap()); assertNotNull(response); } + + @Test + public void testDeleteBackedupAsset() throws Exception { + if (MockableTest.shouldTestFeature(Feature.BACKEDUP_ASSETS)) { + Map result = cloudinary.uploader().upload(SRC_TEST_IMAGE, ObjectUtils.asMap("backup", true)); + + String publicId = (String) result.get("public_id"); + String assetId = (String) result.get("asset_id"); + + ApiResponse getVersionsResp = api.resource(publicId, ObjectUtils.asMap("versions", true)); + List versions = (List) getVersionsResp.get("versions"); + String firstAssetVersion = (String) versions.get(0).get("version_id"); + ApiResponse response = api.deleteBackedUpAssets(assetId, new String[]{firstAssetVersion}, ObjectUtils.emptyMap()); + + assertNotNull(response); + assertEquals(response.get("asset_id"), assetId); + List deletedVersionIds = (List) response.get("deleted_version_ids"); + assertEquals(deletedVersionIds.get(0), firstAssetVersion); + } + } } diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/helpers/Feature.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/helpers/Feature.java index 875f9b9f..aa4297c8 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/helpers/Feature.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/helpers/Feature.java @@ -3,4 +3,5 @@ public class Feature { public static final String ALL = "all"; public static final String DYNAMIC_FOLDERS = "dynamic_folders"; + public static final String BACKEDUP_ASSETS = "backedup_assets"; } From 52d8f8feb029e4f5bedd403576c1e42a75f037dc Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Wed, 8 May 2024 11:34:25 +0300 Subject: [PATCH 117/150] Add config api call --- cloudinary-core/src/main/java/com/cloudinary/Api.java | 10 ++++++++++ .../main/java/com/cloudinary/test/AbstractApiTest.java | 7 +++++++ 2 files changed, 17 insertions(+) diff --git a/cloudinary-core/src/main/java/com/cloudinary/Api.java b/cloudinary-core/src/main/java/com/cloudinary/Api.java index daaa30df..a79409f5 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Api.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Api.java @@ -72,6 +72,16 @@ public ApiResponse usage(Map options) throws Exception { return callApi(HttpMethod.GET, uri, ObjectUtils.emptyMap(), options); } + public ApiResponse configuration(Map options) throws Exception { + if(options == null) options = ObjectUtils.emptyMap(); + + final List uri = new ArrayList(); + uri.add("config"); + + Map params = ObjectUtils.only(options, "settings"); + + return callApi(HttpMethod.GET, uri, params, options); + } public ApiResponse resourceTypes(Map options) throws Exception { if (options == null) options = ObjectUtils.emptyMap(); diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java index 7ffd138e..26726340 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java @@ -668,6 +668,13 @@ public void testRateLimits() throws Exception { Assert.assertNotEquals(0, result.apiRateLimit().getRemaining()); } + @Test + public void testConfiguration() throws Exception { + ApiResponse result = cloudinary.api().configuration(new ObjectUtils().asMap("settings", true)); + Map settings = (Map) result.get("settings"); + Assert.assertNotNull(settings.get("folder_mode")); + } + @Test public void test19Ping() throws Exception { // should support ping API call From 94825e3de8f05848e9913e58fcca70ebd442ffa5 Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Thu, 9 May 2024 11:47:40 +0300 Subject: [PATCH 118/150] Fix rename folder endpoint --- cloudinary-core/src/main/java/com/cloudinary/Api.java | 5 ++--- .../src/main/java/com/cloudinary/test/AbstractApiTest.java | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/cloudinary-core/src/main/java/com/cloudinary/Api.java b/cloudinary-core/src/main/java/com/cloudinary/Api.java index a79409f5..9af8639b 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Api.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Api.java @@ -802,11 +802,10 @@ public ApiResponse analyze(String inputType, String analysisType, String uri, Ma public ApiResponse renameFolder(String path, String toPath, Map options) throws Exception { if (options == null || options.isEmpty()) options = ObjectUtils.asMap(); - List url = Arrays.asList("folder_operations", "rename"); + List url = Arrays.asList("folders", path); final Map params = new HashMap(); - params.put("path", path); - params.put("to_path", toPath); + params.put("to_folder", toPath); return callApi(HttpMethod.PUT, url, params, options); diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java index 26726340..cd1ccc88 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java @@ -1278,11 +1278,11 @@ public void testVisualSearch() { @Test @Ignore("Skip test till FD is enabled for test accounts") public void testRenameFolder() throws Exception { - Map result = api.createFolder("apTestCreateFolder", null); + Map result = api.createFolder("apiTestCreateFolder" + SUFFIX, null); assertNotNull(result); String folderName = (String) result.get("path"); - Map response = api.renameFolder(folderName, "newFolderName", ObjectUtils.emptyMap()); + Map response = api.renameFolder(folderName, "newFolderName" + SUFFIX, ObjectUtils.emptyMap()); assertNotNull(response); } From 922d69198908f84676be5882cab05868c27e686c Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Mon, 1 Jul 2024 13:48:58 +0300 Subject: [PATCH 119/150] Add conditional metadata rules api --- .../src/main/java/com/cloudinary/Api.java | 30 +++++++++ .../com/cloudinary/metadata/MetadataRule.java | 66 +++++++++++++++++++ .../metadata/MetadataRuleCondition.java | 58 ++++++++++++++++ .../metadata/MetadataRuleResult.java | 58 ++++++++++++++++ .../test/AbstractStructuredMetadataTest.java | 52 ++++++++++++++- .../com/cloudinary/test/helpers/Feature.java | 1 + 6 files changed, 264 insertions(+), 1 deletion(-) create mode 100644 cloudinary-core/src/main/java/com/cloudinary/metadata/MetadataRule.java create mode 100644 cloudinary-core/src/main/java/com/cloudinary/metadata/MetadataRuleCondition.java create mode 100644 cloudinary-core/src/main/java/com/cloudinary/metadata/MetadataRuleResult.java diff --git a/cloudinary-core/src/main/java/com/cloudinary/Api.java b/cloudinary-core/src/main/java/com/cloudinary/Api.java index 9af8639b..2899327d 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Api.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Api.java @@ -7,6 +7,7 @@ import com.cloudinary.api.exceptions.*; import com.cloudinary.metadata.MetadataField; import com.cloudinary.metadata.MetadataDataSource; +import com.cloudinary.metadata.MetadataRule; import com.cloudinary.strategies.AbstractApiStrategy; import com.cloudinary.utils.ObjectUtils; import com.cloudinary.utils.StringUtils; @@ -789,6 +790,35 @@ public ApiResponse reorderMetadataFields(String orderBy, String direction, Map o return callApi(HttpMethod.PUT, uri, map, options); } + public ApiResponse listMetadataRules(Map options) throws Exception { + if (options == null || options.isEmpty()) options = ObjectUtils.asMap(); + final Map params = new HashMap(); + List uri = Arrays.asList("metadata_rules"); + return callApi(HttpMethod.GET, uri, params, options); + } + + public ApiResponse addMetadataRule(MetadataRule rule, Map options) throws Exception { + if (options == null || options.isEmpty()) options = ObjectUtils.asMap(); + options.put("content_type", "json"); + final Map params = rule.asMap(); + List uri = Arrays.asList("metadata_rules"); + return callApi(HttpMethod.POST, uri, params, options); + } + + public ApiResponse updateMetadataRule(String externalId, MetadataRule rule, Map options) throws Exception { + if (options == null || options.isEmpty()) options = ObjectUtils.asMap(); + options.put("content_type", "json"); + final Map params = rule.asMap(); + List uri = Arrays.asList("metadata_rules", externalId); + return callApi(HttpMethod.PUT, uri, params, options); + } + + public ApiResponse deleteMetadataRule(String externalId, Map options) throws Exception { + if (options == null || options.isEmpty()) options = ObjectUtils.asMap(); + List uri = Arrays.asList("metadata_rules", externalId); + return callApi(HttpMethod.DELETE, uri, ObjectUtils.emptyMap(), options); + } + public ApiResponse analyze(String inputType, String analysisType, String uri, Map options) throws Exception { if (options == null || options.isEmpty()) options = ObjectUtils.asMap(); List url = Arrays.asList("analysis", "analyze", inputType); diff --git a/cloudinary-core/src/main/java/com/cloudinary/metadata/MetadataRule.java b/cloudinary-core/src/main/java/com/cloudinary/metadata/MetadataRule.java new file mode 100644 index 00000000..65edbed4 --- /dev/null +++ b/cloudinary-core/src/main/java/com/cloudinary/metadata/MetadataRule.java @@ -0,0 +1,66 @@ +package com.cloudinary.metadata; + +import com.cloudinary.utils.ObjectUtils; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +public class MetadataRule { + String metadataFieldId; + String name; + MetadataRuleCondition condition; + MetadataRuleResult result; + + public MetadataRule(String metadataFieldId, String name, MetadataRuleCondition condition, MetadataRuleResult result) { + this.metadataFieldId = metadataFieldId; + this.name = name; + this.condition = condition; + this.result = result; + } + + public String getMetadataFieldId() { + return metadataFieldId; + } + + public void setMetadataFieldId(String metadataFieldId) { + this.metadataFieldId = metadataFieldId; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public MetadataRuleCondition getCondition() { + return condition; + } + + public void setCondition(MetadataRuleCondition condition) { + this.condition = condition; + } + + public MetadataRuleResult getResult() { + return result; + } + + public void setResult(MetadataRuleResult result) { + this.result = result; + } + + public Map asMap() { + Map map = new HashMap(); + map.put("metadata_field_id", getMetadataFieldId()); + map.put("name", getName()); + if (getCondition() != null) { + map.put("condition", ObjectUtils.toJSON(getCondition().asMap())); + } + if(getResult() != null) { + map.put("result", ObjectUtils.toJSON(getResult().asMap())); + } + return map; + } +} diff --git a/cloudinary-core/src/main/java/com/cloudinary/metadata/MetadataRuleCondition.java b/cloudinary-core/src/main/java/com/cloudinary/metadata/MetadataRuleCondition.java new file mode 100644 index 00000000..55e3a714 --- /dev/null +++ b/cloudinary-core/src/main/java/com/cloudinary/metadata/MetadataRuleCondition.java @@ -0,0 +1,58 @@ +package com.cloudinary.metadata; +import java.util.HashMap; +import java.util.Map; + +public class MetadataRuleCondition { + String metadata_field_id; + Boolean populated; + Map includes; + String equals; + + public MetadataRuleCondition(String metadata_field_id, Boolean populated, Map includes, String equals) { + this.metadata_field_id = metadata_field_id; + this.populated = populated; + this.includes = includes; + this.equals = equals; + } + + public String getMetadata_field_id() { + return metadata_field_id; + } + + public void setMetadata_field_id(String metadata_field_id) { + this.metadata_field_id = metadata_field_id; + } + + public Boolean getPopulated() { + return populated; + } + + public void setPopulated(Boolean populated) { + this.populated = populated; + } + + public Map getIncludes() { + return includes; + } + + public void setIncludes(Map includes) { + this.includes = includes; + } + + public String getEquals() { + return equals; + } + + public void setEquals(String equals) { + this.equals = equals; + } + + public Map asMap() { + Map result = new HashMap(4); + result.put("metadata_field_id", metadata_field_id); + result.put("populated", populated); + result.put("includes", includes); + result.put("equals", equals); + return result; + } +} diff --git a/cloudinary-core/src/main/java/com/cloudinary/metadata/MetadataRuleResult.java b/cloudinary-core/src/main/java/com/cloudinary/metadata/MetadataRuleResult.java new file mode 100644 index 00000000..2d4efff0 --- /dev/null +++ b/cloudinary-core/src/main/java/com/cloudinary/metadata/MetadataRuleResult.java @@ -0,0 +1,58 @@ +package com.cloudinary.metadata; + +import java.util.HashMap; +import java.util.Map; + +public class MetadataRuleResult { + Boolean enabled; + String activateValues; + String applyValues; + Boolean setMandatory; + + public MetadataRuleResult(Boolean enabled, String activateValues, String applyValues, Boolean setMandatory) { + this.enabled = enabled; + this.activateValues = activateValues; + this.applyValues = applyValues; + this.setMandatory = setMandatory; + } + + public Boolean getEnabled() { + return enabled; + } + + public void setEnabled(Boolean enabled) { + this.enabled = enabled; + } + + public String getActivateValues() { + return activateValues; + } + + public void setActivateValues(String activateValues) { + this.activateValues = activateValues; + } + + public String getApplyValues() { + return applyValues; + } + + public void setApplyValues(String applyValues) { + this.applyValues = applyValues; + } + + public Boolean getSetMandatory() { + return setMandatory; + } + + public void setSetMandatory(Boolean setMandatory) { + this.setMandatory = setMandatory; + } + public Map asMap() { + Map result = new HashMap(4); + result.put("enable", enabled); + result.put("activate_values", activateValues); + result.put("apply_values", applyValues); + result.put("mandatory", setMandatory); + return result; + } +} diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractStructuredMetadataTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractStructuredMetadataTest.java index bb8f1b9b..d49ac7bb 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractStructuredMetadataTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractStructuredMetadataTest.java @@ -6,6 +6,7 @@ import com.cloudinary.api.exceptions.BadRequest; import com.cloudinary.metadata.*; +import com.cloudinary.test.helpers.Feature; import com.cloudinary.utils.ObjectUtils; import org.hamcrest.Matchers; import org.junit.*; @@ -196,7 +197,7 @@ public void testReorderMetadataFieldsByLabel() throws Exception { AddStringField("some_value"); AddStringField("aaa"); AddStringField("zzz"); - + ApiResponse result = api.reorderMetadataFields("label", null, Collections.EMPTY_MAP); assertThat(getField(result, 0), Matchers.containsString("aaa")); @@ -309,6 +310,55 @@ public void testSetField() throws Exception { assertNotNull(result); assertEquals(PUBLIC_ID, ((List) result.get("public_ids")).get(0).toString()); } + + @Test + public void testListMetadataRules() throws Exception { + Assume.assumeTrue(MockableTest.shouldTestFeature(Feature.CONDITIONAL_METADATA_RULES)); + ApiResponse result = cloudinary.api().listMetadataRules(null); + assertNotNull(result); + } + + @Test + public void testAddMetadataRule() throws Exception { + Assume.assumeTrue(MockableTest.shouldTestFeature(Feature.CONDITIONAL_METADATA_RULES)); + SetMetadataField field = createSetField("test123"); + ApiResponse response = addFieldToAccount(field); + assertNotNull(response); + + String externalId = (String) response.get("external_id"); + MetadataRule rule = new MetadataRule(externalId, "category-employee", new MetadataRuleCondition("category", false, null, "employee"), new MetadataRuleResult(true, "all", null, null)); + ApiResponse result = cloudinary.api().addMetadataRule(rule, ObjectUtils.asMap()); + assertNotNull(result); + + String name = (String) result.get("name"); + assertEquals(name, "category-employee"); + } + + @Test + public void testUpdateMetadataRule() throws Exception { + Assume.assumeTrue(MockableTest.shouldTestFeature(Feature.CONDITIONAL_METADATA_RULES)); + ApiResponse response = cloudinary.api().listMetadataRules(null); + List metadataRules = (List) response.get("metadata_rules"); + assertNotNull(metadataRules); + String externalId = (String) ((Map) metadataRules.get(0)).get("external_id"); + + MetadataRule rule = new MetadataRule(null, "test_name", null, null); + ApiResponse result = cloudinary.api().updateMetadataRule(externalId, rule, ObjectUtils.asMap()); + assertNotNull(result); + } + + @Test + public void testDeleteMetadataRule() throws Exception { + Assume.assumeTrue(MockableTest.shouldTestFeature(Feature.CONDITIONAL_METADATA_RULES)); + ApiResponse response = cloudinary.api().listMetadataRules(null); + List metadataRules = (List) response.get("metadata_rules"); + assertNotNull(metadataRules); + String externalId = (String) ((Map) metadataRules.get(0)).get("external_id"); + + ApiResponse result = cloudinary.api().deleteMetadataRule(externalId, ObjectUtils.emptyMap()); + assertNotNull(result); + } + // Metadata test helpers private SetMetadataField createSetField(String labelPrefix) { SetMetadataField setField = new SetMetadataField(); diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/helpers/Feature.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/helpers/Feature.java index aa4297c8..2ced269c 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/helpers/Feature.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/helpers/Feature.java @@ -4,4 +4,5 @@ public class Feature { public static final String ALL = "all"; public static final String DYNAMIC_FOLDERS = "dynamic_folders"; public static final String BACKEDUP_ASSETS = "backedup_assets"; + public static final String CONDITIONAL_METADATA_RULES = "conditional_metadata_rules"; } From 2caecfd0273bcfd2bb9cf6b572c9b5b3de37e78c Mon Sep 17 00:00:00 2001 From: adimiz1 Date: Sun, 14 Jul 2024 11:14:35 +0300 Subject: [PATCH 120/150] Version 1.39.0 --- CHANGELOG.md | 13 +++++++++++++ README.md | 4 ++-- .../src/main/java/com/cloudinary/Cloudinary.java | 2 +- gradle.properties | 2 +- 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a520f7d..f4b4cc2c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,16 @@ +1.39.0 / 2024-07-14 +=================== + +* Add conditional metadata rules api +* Fix rename folder endpoint +* Add config api call +* Add delete backup asset version support +* Add rename folder api support +* Add analyze api +* Add selective response support +* Add access key management +* Add restrictions field to metadata + 1.38.0 / 2024-02-18 =================== diff --git a/README.md b/README.md index b4eb9244..42a635c6 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ For the complete documentation, see the [Java SDK Guide](https://cloudinary.com/ ## Version Support | SDK Version | Java 6+ | |----------------|---------| -| 1.1.0 - 1.38.0 | V | +| 1.1.0 - 1.39.0 | V | ## Installation The cloudinary_java library is available in [Maven Central](https://mvnrepository.com/artifact/com.cloudinary/cloudinary-core). To use it, add the following dependency to your pom.xml : @@ -36,7 +36,7 @@ The cloudinary_java library is available in [Maven Central](https://mvnrepositor com.cloudinary cloudinary-http45 - 1.38.0 + 1.39.0 ``` diff --git a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java index af553631..24e6f692 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java @@ -38,7 +38,7 @@ public class Cloudinary { public final static String AKAMAI_SHARED_CDN = "res.cloudinary.com"; public final static String SHARED_CDN = AKAMAI_SHARED_CDN; - public final static String VERSION = "1.38.0"; + public final static String VERSION = "1.39.0"; static String USER_AGENT_PREFIX = "CloudinaryJava"; public final static String USER_AGENT_JAVA_VERSION = "(Java " + System.getProperty("java.version") + ")"; diff --git a/gradle.properties b/gradle.properties index b3933bac..e588ea7d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,7 +13,7 @@ developerEmail=info@cloudinary.com # These two properties must use these exact names to be compatible with 'gradle install' plugin. group=com.cloudinary -version=1.38.0 +version=1.39.0 gnsp.disableApplyOnlyOnRootProjectEnforcement=true From f4c574389c3689457743ddbd76436a4c35bfff31 Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Mon, 15 Jul 2024 15:18:12 +0300 Subject: [PATCH 121/150] Add support for update metadata field set default disabled --- .../cloudinary/metadata/MetadataField.java | 9 ++++++ .../com/cloudinary/test/AbstractApiTest.java | 6 ++-- .../test/AbstractStructuredMetadataTest.java | 30 ++++++++++--------- .../cloudinary/test/AbstractUploaderTest.java | 2 +- .../cloudinary/test/MetadataTestHelper.java | 4 +-- 5 files changed, 31 insertions(+), 20 deletions(-) diff --git a/cloudinary-core/src/main/java/com/cloudinary/metadata/MetadataField.java b/cloudinary-core/src/main/java/com/cloudinary/metadata/MetadataField.java index 7dee301f..4f3bdf33 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/metadata/MetadataField.java +++ b/cloudinary-core/src/main/java/com/cloudinary/metadata/MetadataField.java @@ -17,6 +17,7 @@ public class MetadataField extends JSONObject { public static final String TYPE = "type"; public static final String VALIDATION = "validation"; public static final String RESTRICTIONS = "restrictions"; + public static final String DEFAULT_DISABLED = "default_disabled"; public MetadataField(MetadataFieldType type) { put(TYPE, type.toString()); @@ -139,4 +140,12 @@ public void setDataSource(MetadataDataSource dataSource) { public void setRestrictions(Restrictions restrictions) { put(RESTRICTIONS, restrictions.toHash()); } + + /** + * Set the value indicating whether the field should be disabled by default + * @param disabled The value to set. + */ + public void setDefaultDisabled(Boolean disabled) { + put(DEFAULT_DISABLED, disabled); + } } \ No newline at end of file diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java index cd1ccc88..dd3802c9 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java @@ -415,7 +415,7 @@ public void testDeleteDerivedByTransformation() throws Exception { @Test public void testGetResourcesWithMetadata() throws Exception { String public_id = "api_,withMetadata" + SUFFIX; - String fieldId = MetadataTestHelper.addFieldToAccount(api, MetadataTestHelper.newFieldInstance("some_field" + SUFFIX)).get("external_id").toString(); + String fieldId = MetadataTestHelper.addFieldToAccount(api, MetadataTestHelper.newFieldInstance("some_field" + SUFFIX, true)).get("external_id").toString(); cloudinary.uploader().upload(SRC_TEST_IMAGE, ObjectUtils.asMap("public_id", public_id, "tags", UPLOAD_TAGS, @@ -761,8 +761,8 @@ public void testDetectionUpdate() { @Test public void testUpdateResourceClearInvalid() throws Exception { - String fieldId = MetadataTestHelper.addFieldToAccount(api, MetadataTestHelper.newFieldInstance("some_field3" + SUFFIX)).get("external_id").toString(); - String fieldId2 = MetadataTestHelper.addFieldToAccount(api, MetadataTestHelper.newFieldInstance("some_field4" + SUFFIX)).get("external_id").toString(); + String fieldId = MetadataTestHelper.addFieldToAccount(api, MetadataTestHelper.newFieldInstance("some_field3" + SUFFIX, true)).get("external_id").toString(); + String fieldId2 = MetadataTestHelper.addFieldToAccount(api, MetadataTestHelper.newFieldInstance("some_field4" + SUFFIX, true)).get("external_id").toString(); Map uploadResult = cloudinary.uploader().upload(SRC_TEST_IMAGE, ObjectUtils.asMap("tags", UPLOAD_TAGS, "metadata", ObjectUtils.asMap(fieldId, "test"))); Map apiResult = api.update((String) uploadResult.get("public_id"), ObjectUtils.asMap("clear_invalid", true, "metadata", ObjectUtils.asMap(fieldId2, "test2"))); diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractStructuredMetadataTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractStructuredMetadataTest.java index d49ac7bb..241ac47d 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractStructuredMetadataTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractStructuredMetadataTest.java @@ -62,7 +62,7 @@ public void setUp() { @Test public void testCreateMetadata() throws Exception { - StringMetadataField stringField = newFieldInstance("testCreateMetadata_1"); + StringMetadataField stringField = newFieldInstance("testCreateMetadata_1", true); ApiResponse result = addFieldToAccount(stringField); assertNotNull(result); assertEquals(stringField.getLabel(), result.get("label")); @@ -75,7 +75,7 @@ public void testCreateMetadata() throws Exception { @Test public void testFieldRestrictions() throws Exception { - StringMetadataField stringField = newFieldInstance("testCreateMetadata_3"); + StringMetadataField stringField = newFieldInstance("testCreateMetadata_3", true); stringField.setRestrictions(new Restrictions().setReadOnlyUI()); ApiResponse result = api.addMetadataField(stringField); @@ -124,7 +124,7 @@ public void testDateFieldDefaultValueValidation() throws Exception { @Test public void testListFields() throws Exception { - StringMetadataField stringField = newFieldInstance("testListFields"); + StringMetadataField stringField = newFieldInstance("testListFields", true); addFieldToAccount(stringField); ApiResponse result = cloudinary.api().listMetadataFields(); @@ -135,7 +135,7 @@ public void testListFields() throws Exception { @Test public void testGetMetadata() throws Exception { - ApiResponse fieldResult = addFieldToAccount(newFieldInstance("testGetMetadata")); + ApiResponse fieldResult = addFieldToAccount(newFieldInstance("testGetMetadata", true)); ApiResponse result = api.metadataFieldByFieldId(fieldResult.get("external_id").toString()); assertNotNull(result); assertEquals(fieldResult.get("label"), result.get("label")); @@ -143,14 +143,16 @@ public void testGetMetadata() throws Exception { @Test public void testUpdateField() throws Exception { - StringMetadataField metadataField = newFieldInstance("testUpdateField"); + StringMetadataField metadataField = newFieldInstance("testUpdateField", false); ApiResponse fieldResult = addFieldToAccount(metadataField); assertNotEquals("new_def", fieldResult.get("default_value")); metadataField.setDefaultValue("new_def"); + metadataField.setDefaultDisabled(true); metadataField.setRestrictions(new Restrictions().setReadOnlyUI()); ApiResponse result = api.updateMetadataField(fieldResult.get("external_id").toString(), metadataField); assertNotNull(result); assertEquals("new_def", result.get("default_value")); + assertEquals(true, result.get("default_disabled")); Map restrictions = (Map) result.get("restrictions"); assertNotNull(restrictions); assertTrue((Boolean)restrictions.get("readonly_ui")); @@ -158,7 +160,7 @@ public void testUpdateField() throws Exception { @Test public void testDeleteField() throws Exception { - ApiResponse fieldResult = addFieldToAccount(newFieldInstance("testDeleteField")); + ApiResponse fieldResult = addFieldToAccount(newFieldInstance("testDeleteField", true)); ApiResponse result = api.deleteMetadataField(fieldResult.get("external_id").toString()); assertNotNull(result); assertEquals("ok", result.get("message")); @@ -219,14 +221,14 @@ private String getField(ApiResponse result, int index) { } private void AddStringField(String labelPrefix) throws Exception { - StringMetadataField field = newFieldInstance(labelPrefix); + StringMetadataField field = newFieldInstance(labelPrefix, true); ApiResponse fieldResult = addFieldToAccount(field); String fieldId = fieldResult.get("external_id").toString(); } @Test public void testUploadWithMetadata() throws Exception { - StringMetadataField field = newFieldInstance("testUploadWithMetadata"); + StringMetadataField field = newFieldInstance("testUploadWithMetadata", true); ApiResponse fieldResult = addFieldToAccount(field); String fieldId = fieldResult.get("external_id").toString(); Map metadata = Collections.singletonMap(fieldId, "123456"); @@ -239,7 +241,7 @@ public void testUploadWithMetadata() throws Exception { public void testExplicitWithMetadata() throws Exception { Map uploadResult = cloudinary.uploader().upload(SRC_TEST_IMAGE, asMap("tags", Arrays.asList(SDK_TEST_TAG, METADATA_UPLOADER_TAG))); String publicId = uploadResult.get("public_id").toString(); - StringMetadataField field = newFieldInstance("testExplicitWithMetadata"); + StringMetadataField field = newFieldInstance("testExplicitWithMetadata", true); ApiResponse fieldResult = addFieldToAccount(field); String fieldId = fieldResult.get("external_id").toString(); Map metadata = Collections.singletonMap(fieldId, "123456"); @@ -263,7 +265,7 @@ public void testExplicitWithMetadata() throws Exception { public void testUpdateWithMetadata() throws Exception { Map uploadResult = cloudinary.uploader().upload(SRC_TEST_IMAGE, asMap("tags", Arrays.asList(SDK_TEST_TAG, METADATA_UPLOADER_TAG))); String publicId = uploadResult.get("public_id").toString(); - StringMetadataField field = newFieldInstance("testUpdateWithMetadata"); + StringMetadataField field = newFieldInstance("testUpdateWithMetadata", true); ApiResponse fieldResult = addFieldToAccount(field); String fieldId = fieldResult.get("external_id").toString(); Map metadata = Collections.singletonMap(fieldId, "123456"); @@ -274,7 +276,7 @@ public void testUpdateWithMetadata() throws Exception { @Test public void testUploaderUpdateMetadata() throws Exception { - StringMetadataField field = newFieldInstance("testUploaderUpdateMetadata"); + StringMetadataField field = newFieldInstance("testUploaderUpdateMetadata", true); ApiResponse fieldResult = addFieldToAccount(field); String fieldId = fieldResult.get("external_id").toString(); Map result = cloudinary.uploader().updateMetadata(Collections.singletonMap(fieldId, "123456"), new String[]{PUBLIC_ID}, null); @@ -288,7 +290,7 @@ public void testUploaderUpdateMetadata() throws Exception { @Test public void testUploaderUpdateMetadataClearInvalid() throws Exception { - StringMetadataField field = newFieldInstance("testUploaderUpdateMetadata1"); + StringMetadataField field = newFieldInstance("testUploaderUpdateMetadata1", true); ApiResponse fieldResult = addFieldToAccount(field); String fieldId = fieldResult.get("external_id").toString(); Map result = cloudinary.uploader().updateMetadata(Collections.singletonMap(fieldId, "123456"), new String[]{PUBLIC_ID}, ObjectUtils.asMap("clear_invalid", true)); @@ -377,9 +379,9 @@ private SetMetadataField createSetField(String labelPrefix) { return setField; } - private StringMetadataField newFieldInstance(String labelPrefix) throws Exception { + private StringMetadataField newFieldInstance(String labelPrefix, Boolean mandatory) throws Exception { String label = labelPrefix + "_" + SUFFIX; - return MetadataTestHelper.newFieldInstance(label); + return MetadataTestHelper.newFieldInstance(label, mandatory); } private ApiResponse addFieldToAccount(MetadataField field) throws Exception { diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java index bddf48cc..99654c4e 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java @@ -236,7 +236,7 @@ public void testRenameShouldReturnContext() throws Exception { @Test public void testRenameShouldReturnMetadata() throws Exception { String label = "test" + SUFFIX; - StringMetadataField f = MetadataTestHelper.newFieldInstance(label); + StringMetadataField f = MetadataTestHelper.newFieldInstance(label, true); Map fieldResult = MetadataTestHelper.addFieldToAccount(cloudinary.api(), f); String fieldId = fieldResult.get("external_id").toString(); Map metadata = Collections.singletonMap(fieldId, "123456"); diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/MetadataTestHelper.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/MetadataTestHelper.java index d130b282..cdb52487 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/MetadataTestHelper.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/MetadataTestHelper.java @@ -7,10 +7,10 @@ import com.cloudinary.metadata.StringMetadataField; public class MetadataTestHelper { - public static StringMetadataField newFieldInstance(String label) throws Exception { + public static StringMetadataField newFieldInstance(String label, Boolean mandatory) throws Exception { StringMetadataField field = new StringMetadataField(); field.setLabel(label); - field.setMandatory(true); + field.setMandatory(mandatory); field.setValidation(new MetadataValidation.StringLength(3, 9)); field.setDefaultValue("val_test"); return field; From 5553c36e22ecff46ced3db4a8c2157629816269f Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Tue, 30 Jul 2024 17:42:55 +0300 Subject: [PATCH 122/150] Implement major version requirements --- .../java/com/cloudinary/Configuration.java | 4 +- .../java/com/cloudinary/AuthTokenTest.java | 16 +-- .../cloudinary/analytics/AnalyticsTest.java | 16 +-- .../com/cloudinary/test/CloudinaryTest.java | 113 +++++++++--------- .../cloudinary/transformation/LayerTest.java | 6 +- .../cloudinary/test/AbstractUploaderTest.java | 2 + 6 files changed, 80 insertions(+), 77 deletions(-) diff --git a/cloudinary-core/src/main/java/com/cloudinary/Configuration.java b/cloudinary-core/src/main/java/com/cloudinary/Configuration.java index b0dcc41f..07280d89 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Configuration.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Configuration.java @@ -114,7 +114,7 @@ public void update(Map config) { this.apiSecret = (String) config.get("api_secret"); this.secureDistribution = (String) config.get("secure_distribution"); this.cname = (String) config.get("cname"); - this.secure = ObjectUtils.asBoolean(config.get("secure"), false); + this.secure = ObjectUtils.asBoolean(config.get("secure"), true); this.privateCdn = ObjectUtils.asBoolean(config.get("private_cdn"), false); this.cdnSubdomain = ObjectUtils.asBoolean(config.get("cdn_subdomain"), false); this.shorten = ObjectUtils.asBoolean(config.get("shorten"), false); @@ -128,7 +128,7 @@ public void update(Map config) { this.loadStrategies = ObjectUtils.asBoolean(config.get("load_strategies"), true); this.timeout = ObjectUtils.asInteger(config.get("timeout"), 0); this.clientHints = ObjectUtils.asBoolean(config.get("client_hints"), false); - this.analytics = ObjectUtils.asBoolean(config.get("analytics"), null); + this.analytics = ObjectUtils.asBoolean(config.get("analytics"), true); Map tokenMap = (Map) config.get("auth_token"); if (tokenMap != null) { this.authToken = new AuthToken(tokenMap); diff --git a/cloudinary-core/src/test/java/com/cloudinary/AuthTokenTest.java b/cloudinary-core/src/test/java/com/cloudinary/AuthTokenTest.java index ca30479e..468c43bb 100644 --- a/cloudinary-core/src/test/java/com/cloudinary/AuthTokenTest.java +++ b/cloudinary-core/src/test/java/com/cloudinary/AuthTokenTest.java @@ -32,7 +32,7 @@ public class AuthTokenTest { @Before public void setUp() { System.out.println("Running " + this.getClass().getName() + "." + currentTest.getMethodName()); - this.cloudinary = new Cloudinary("cloudinary://a:b@test123?load_strategies=false"); + this.cloudinary = new Cloudinary("cloudinary://a:b@test123?load_strategies=false&analytics=false"); final AuthToken authToken = new AuthToken(KEY).duration(300); authToken.startTime(11111111); // start time is set for test purposes cloudinary.config.authToken = authToken; @@ -74,28 +74,28 @@ public void testAuthenticatedUrl() { String message = "should add token if authToken is globally set and signed = true"; String url = cloudinary.url().signed(true).resourceType("image").type("authenticated").version("1486020273").generate("sample.jpg"); - assertEquals(message,"http://test123-res.cloudinary.com/image/authenticated/v1486020273/sample.jpg?__cld_token__=st=11111111~exp=11111411~hmac=8db0d753ee7bbb9e2eaf8698ca3797436ba4c20e31f44527e43b6a6e995cfdb3", url); + assertEquals(message,"https://test123-res.cloudinary.com/image/authenticated/v1486020273/sample.jpg?__cld_token__=st=11111111~exp=11111411~hmac=8db0d753ee7bbb9e2eaf8698ca3797436ba4c20e31f44527e43b6a6e995cfdb3", url); message = "should add token for 'public' resource"; url = cloudinary.url().signed(true).resourceType("image").type("public").version("1486020273").generate("sample.jpg"); - assertEquals(message,"http://test123-res.cloudinary.com/image/public/v1486020273/sample.jpg?__cld_token__=st=11111111~exp=11111411~hmac=c2b77d9f81be6d89b5d0ebc67b671557e88a40bcf03dd4a6997ff4b994ceb80e", url); + assertEquals(message,"https://test123-res.cloudinary.com/image/public/v1486020273/sample.jpg?__cld_token__=st=11111111~exp=11111411~hmac=c2b77d9f81be6d89b5d0ebc67b671557e88a40bcf03dd4a6997ff4b994ceb80e", url); message = "should not add token if signed is false"; url = cloudinary.url().resourceType("image").type("authenticated").version("1486020273").generate("sample.jpg"); - assertEquals(message,"http://test123-res.cloudinary.com/image/authenticated/v1486020273/sample.jpg", url); + assertEquals(message,"https://test123-res.cloudinary.com/image/authenticated/v1486020273/sample.jpg", url); message = "should not add token if authToken is globally set but null auth token is explicitly set and signed = true"; url = cloudinary.url().authToken(AuthToken.NULL_AUTH_TOKEN).signed(true).resourceType("image").type("authenticated").version("1486020273").generate("sample.jpg"); - assertEquals(message,"http://test123-res.cloudinary.com/image/authenticated/s--v2fTPYTu--/v1486020273/sample.jpg", url); + assertEquals(message,"https://test123-res.cloudinary.com/image/authenticated/s--v2fTPYTu--/v1486020273/sample.jpg", url); message = "explicit authToken should override global setting"; url = cloudinary.url().signed(true).authToken(new AuthToken(ALT_KEY).startTime(222222222).duration(100)).resourceType("image").type("authenticated").transformation(new Transformation().crop("scale").width(300)).generate("sample.jpg"); - assertEquals(message,"http://test123-res.cloudinary.com/image/authenticated/c_scale,w_300/sample.jpg?__cld_token__=st=222222222~exp=222222322~hmac=55cfe516530461213fe3b3606014533b1eca8ff60aeab79d1bb84c9322eebc1f", url); + assertEquals(message,"https://test123-res.cloudinary.com/image/authenticated/c_scale,w_300/sample.jpg?__cld_token__=st=222222222~exp=222222322~hmac=55cfe516530461213fe3b3606014533b1eca8ff60aeab79d1bb84c9322eebc1f", url); message = "should compute expiration as start time + duration"; url = cloudinary.url().signed(true).authToken(new AuthToken().startTime(11111111).duration(300)) .type("authenticated").version("1486020273").generate("sample.jpg"); - assertEquals(message,"http://test123-res.cloudinary.com/image/authenticated/v1486020273/sample.jpg?__cld_token__=st=11111111~exp=11111411~hmac=8db0d753ee7bbb9e2eaf8698ca3797436ba4c20e31f44527e43b6a6e995cfdb3", url); + assertEquals(message,"https://test123-res.cloudinary.com/image/authenticated/v1486020273/sample.jpg?__cld_token__=st=11111111~exp=11111411~hmac=8db0d753ee7bbb9e2eaf8698ca3797436ba4c20e31f44527e43b6a6e995cfdb3", url); } @@ -120,7 +120,7 @@ public void testTokenGeneration(){ public void testUrlInTag() { String message = "should add token to an image tag url"; String url = cloudinary.url().signed(true).resourceType("image").type("authenticated").version("1486020273").imageTag("sample.jpg"); - assertThat(url, Matchers.matchesPattern("")); + assertThat(url, Matchers.matchesPattern("")); } diff --git a/cloudinary-core/src/test/java/com/cloudinary/analytics/AnalyticsTest.java b/cloudinary-core/src/test/java/com/cloudinary/analytics/AnalyticsTest.java index 6300947e..e87143c6 100644 --- a/cloudinary-core/src/test/java/com/cloudinary/analytics/AnalyticsTest.java +++ b/cloudinary-core/src/test/java/com/cloudinary/analytics/AnalyticsTest.java @@ -65,26 +65,28 @@ public void testUrlWithAnalytics() { cloudinary.config.analytics = true; cloudinary.setAnalytics(new Analytics("F", "2.0.0", "1.8.0", "Z", "1.34.0", "0")); String url = cloudinary.url().generate("test"); - Assert.assertEquals(url, "http://res.cloudinary.com/test123/image/upload/test?_a=DAFAACMhZBi0"); + Assert.assertEquals(url, "https://res.cloudinary.com/test123/image/upload/test?_a=DAFAACMhZBi0"); } @Test public void testUrlWithNoAnalytics() { - String url = cloudinary.url().generate("test"); - Assert.assertEquals(url, "http://res.cloudinary.com/test123/image/upload/test"); + cloudinary.config.analytics = false; + String url = cloudinary.url().secure(true).generate("test"); + Assert.assertEquals(url, "https://res.cloudinary.com/test123/image/upload/test"); } @Test public void testUrlWithNoAnalyticsDefined() { cloudinary.config.analytics = false; String url = cloudinary.url().generate("test"); - Assert.assertEquals(url, "http://res.cloudinary.com/test123/image/upload/test"); + Assert.assertEquals(url, "https://res.cloudinary.com/test123/image/upload/test"); } @Test public void testUrlWithNoAnalyticsNull() { + cloudinary.config.analytics = false; String url = cloudinary.url().generate("test"); - Assert.assertEquals(url, "http://res.cloudinary.com/test123/image/upload/test"); + Assert.assertEquals(url, "https://res.cloudinary.com/test123/image/upload/test"); } @Test @@ -93,7 +95,7 @@ public void testUrlWithNoAnalyticsNullAndTrue() { cloudinary.analytics.setSDKSemver("1.30.0"); cloudinary.analytics.setTechVersion("12.0.0"); String url = cloudinary.url().generate("test"); - Assert.assertEquals(url, "http://res.cloudinary.com/test123/image/upload/test?_a=DAGAu5AMZAA0"); + Assert.assertEquals(url, "https://res.cloudinary.com/test123/image/upload/test?_a=DAGAu5AMZAA0"); } @Test @@ -123,7 +125,7 @@ public void testUrlNoAnalyticsWithQueryParams() { cloudinary.setAnalytics(new Analytics("F", "2.0.0", System.getProperty("java.version"), "Z", System.getProperty("os.version"), "0")); cloudinary.config.privateCdn = true; String url = cloudinary.url().signed(true).type("authenticated").generate("test"); - assertEquals(url,"http://test123-res.cloudinary.com/image/authenticated/test?__cld_token__=st=11111111~exp=11111411~hmac=735a49389a72ac0b90d1a84ac5d43facd1a9047f153b39e914747ef6ed195e53"); + assertEquals(url,"https://test123-res.cloudinary.com/image/authenticated/test?__cld_token__=st=11111111~exp=11111411~hmac=735a49389a72ac0b90d1a84ac5d43facd1a9047f153b39e914747ef6ed195e53"); cloudinary.config.privateCdn = false; } diff --git a/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java b/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java index f23acd60..0721acae 100644 --- a/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java +++ b/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java @@ -35,7 +35,7 @@ @RunWith(JUnitParamsRunner.class) public class CloudinaryTest { - private static final String DEFAULT_ROOT_PATH = "http://res.cloudinary.com/test123/"; + private static final String DEFAULT_ROOT_PATH = "https://res.cloudinary.com/test123/"; private static final String DEFAULT_UPLOAD_PATH = DEFAULT_ROOT_PATH + "image/upload/"; private static final String VIDEO_UPLOAD_PATH = DEFAULT_ROOT_PATH + "video/upload/"; private Cloudinary cloudinary; @@ -46,7 +46,7 @@ public class CloudinaryTest { @Before public void setUp() { System.out.println("Running " + this.getClass().getName() + "." + currentTest.getMethodName()); - this.cloudinary = new Cloudinary("cloudinary://a:b@test123?load_strategies=false"); + this.cloudinary = new Cloudinary("cloudinary://a:b@test123?load_strategies=false&analytics=false"); } @Test @@ -93,13 +93,13 @@ public void testCloudName() { public void testCloudNameOptions() { // should allow overriding cloud_name in options String result = cloudinary.url().cloudName("test321").generate("test"); - assertEquals("http://res.cloudinary.com/test321/image/upload/test", result); + assertEquals("https://res.cloudinary.com/test321/image/upload/test", result); } @Test public void testSecureDistribution() { // should use default secure distribution if secure=TRUE - String result = cloudinary.url().secure(true).generate("test"); + String result = cloudinary.url().generate("test"); assertEquals("https://res.cloudinary.com/test123/image/upload/test", result); } @@ -113,7 +113,7 @@ public void testTextLayerStyleIdentifierVariables() { new TextLayer().text("hello-world").textStyle("$style") )).generate("sample"); - assertEquals("http://res.cloudinary.com/test123/image/upload/$style_!Arial_12!/l_text:$style:hello-world/sample", url); + assertEquals("https://res.cloudinary.com/test123/image/upload/$style_!Arial_12!/l_text:$style:hello-world/sample", url); url = cloudinary.url().transformation( new Transformation() @@ -123,14 +123,14 @@ public void testTextLayerStyleIdentifierVariables() { new TextLayer().text("hello-world").textStyle(new Expression("$style")) )).generate("sample"); - assertEquals("http://res.cloudinary.com/test123/image/upload/$style_!Arial_12!/l_text:$style:hello-world/sample", url); + assertEquals("https://res.cloudinary.com/test123/image/upload/$style_!Arial_12!/l_text:$style:hello-world/sample", url); } @Test public void testSecureDistributionOverwrite() { // should allow overwriting secure distribution if secure=TRUE - String result = cloudinary.url().secure(true).secureDistribution("something.else.com").generate("test"); + String result = cloudinary.url().secureDistribution("something.else.com").generate("test"); assertEquals("https://something.else.com/test123/image/upload/test", result); } @@ -146,7 +146,6 @@ public void testSecureDistibution() { public void testSecureAkamai() { // should default to akamai if secure is given with private_cdn and no // secure_distribution - cloudinary.config.secure = true; cloudinary.config.privateCdn = true; String result = cloudinary.url().generate("test"); assertEquals("https://test123-res.cloudinary.com/image/upload/test", result); @@ -156,7 +155,6 @@ public void testSecureAkamai() { public void testSecureNonAkamai() { // should not add cloud_name if private_cdn and secure non akamai // secure_distribution - cloudinary.config.secure = true; cloudinary.config.privateCdn = true; cloudinary.config.secureDistribution = "something.cloudfront.net"; String result = cloudinary.url().generate("test"); @@ -168,7 +166,7 @@ public void testHttpPrivateCdn() { // should not add cloud_name if private_cdn and not secure cloudinary.config.privateCdn = true; String result = cloudinary.url().generate("test"); - assertEquals("http://test123-res.cloudinary.com/image/upload/test", result); + assertEquals("https://test123-res.cloudinary.com/image/upload/test", result); } @Test @@ -182,14 +180,14 @@ public void testFormat() { public void testType() { // should use type from options String result = cloudinary.url().type("facebook").generate("test"); - assertEquals("http://res.cloudinary.com/test123/image/facebook/test", result); + assertEquals("https://res.cloudinary.com/test123/image/facebook/test", result); } @Test public void testResourceType() { // should use resource_type from options String result = cloudinary.url().resourcType("raw").generate("test"); - assertEquals("http://res.cloudinary.com/test123/raw/upload/test", result); + assertEquals("https://res.cloudinary.com/test123/raw/upload/test", result); } @Test @@ -200,27 +198,27 @@ public void testIgnoreHttp() { result = cloudinary.url().type("asset").generate("http://test"); assertEquals("http://test", result); result = cloudinary.url().type("fetch").generate("http://test"); - assertEquals("http://res.cloudinary.com/test123/image/fetch/http://test", result); + assertEquals("https://res.cloudinary.com/test123/image/fetch/http://test", result); } @Test public void testFetch() { // should escape fetch urls String result = cloudinary.url().type("fetch").generate("http://blah.com/hello?a=b"); - assertEquals("http://res.cloudinary.com/test123/image/fetch/http://blah.com/hello%3Fa%3Db", result); + assertEquals("https://res.cloudinary.com/test123/image/fetch/http://blah.com/hello%3Fa%3Db", result); } @Test public void testCname() { // should support external cname - String result = cloudinary.url().cname("hello.com").generate("test"); + String result = cloudinary.url().cname("hello.com").secure(false).generate("test"); assertEquals("http://hello.com/test123/image/upload/test", result); } @Test public void testCnameSubdomain() { // should support external cname with cdn_subdomain on - String result = cloudinary.url().cname("hello.com").cdnSubdomain(true).generate("test"); + String result = cloudinary.url().cname("hello.com").cdnSubdomain(true).secure(false).generate("test"); assertEquals("http://a2.hello.com/test123/image/upload/test", result); } @@ -243,17 +241,17 @@ public void testDisallowUrlSuffixWithDot() { @Test public void testSupportUrlSuffixForPrivateCdn() { String actual = cloudinary.url().suffix("hello").privateCdn(true).generate("test"); - assertEquals("http://test123-res.cloudinary.com/images/test/hello", actual); + assertEquals("https://test123-res.cloudinary.com/images/test/hello", actual); actual = cloudinary.url().suffix("hello").privateCdn(true).transformation(new Transformation().angle(0)).generate("test"); - assertEquals("http://test123-res.cloudinary.com/images/a_0/test/hello", actual); + assertEquals("https://test123-res.cloudinary.com/images/a_0/test/hello", actual); } @Test public void testPutFormatAfterUrlSuffix() { String actual = cloudinary.url().suffix("hello").privateCdn(true).format("jpg").generate("test"); - assertEquals("http://test123-res.cloudinary.com/images/test/hello.jpg", actual); + assertEquals("https://test123-res.cloudinary.com/images/test/hello.jpg", actual); } @Test @@ -266,7 +264,7 @@ public void testNotSignTheUrlSuffix() { String expectedSignature = url.substring(matcher.start(), matcher.end()); String actual = cloudinary.url().format("jpg").privateCdn(true).signed(true).suffix("hello").generate("test"); - assertEquals("http://test123-res.cloudinary.com/images/" + expectedSignature + "/test/hello.jpg", actual); + assertEquals("https://test123-res.cloudinary.com/images/" + expectedSignature + "/test/hello.jpg", actual); url = cloudinary.url().format("jpg").signed(true).transformation(new Transformation().angle(0)).generate("test"); matcher = pattern.matcher(url); @@ -275,56 +273,56 @@ public void testNotSignTheUrlSuffix() { actual = cloudinary.url().format("jpg").privateCdn(true).signed(true).suffix("hello").transformation(new Transformation().angle(0)).generate("test"); - assertEquals("http://test123-res.cloudinary.com/images/" + expectedSignature + "/a_0/test/hello.jpg", actual); + assertEquals("https://test123-res.cloudinary.com/images/" + expectedSignature + "/a_0/test/hello.jpg", actual); } @Test public void testSignatureLength(){ String url = cloudinary.url().signed(true).generate("sample.jpg"); - assertEquals("http://res.cloudinary.com/test123/image/upload/s--v2fTPYTu--/sample.jpg", url); + assertEquals("https://res.cloudinary.com/test123/image/upload/s--v2fTPYTu--/sample.jpg", url); url = cloudinary.url().signed(true).longUrlSignature(true).generate("sample.jpg"); - assertEquals("http://res.cloudinary.com/test123/image/upload/s--2hbrSMPOjj5BJ4xV7SgFbRDevFaQNUFf--/sample.jpg", url); + assertEquals("https://res.cloudinary.com/test123/image/upload/s--2hbrSMPOjj5BJ4xV7SgFbRDevFaQNUFf--/sample.jpg", url); } @Test public void testSupportUrlSuffixForRawUploads() { String actual = cloudinary.url().suffix("hello").privateCdn(true).resourceType("raw").generate("test"); - assertEquals("http://test123-res.cloudinary.com/files/test/hello", actual); + assertEquals("https://test123-res.cloudinary.com/files/test/hello", actual); } @Test public void testSupportUrlSuffixForVideoUploads() { String actual = cloudinary.url().suffix("hello").privateCdn(true).resourceType("video").generate("test"); - assertEquals("http://test123-res.cloudinary.com/videos/test/hello", actual); + assertEquals("https://test123-res.cloudinary.com/videos/test/hello", actual); } @Test public void testSupportUrlSuffixForAuthenticatedImages() { String actual = cloudinary.url().suffix("hello").privateCdn(true).resourceType("image").type("authenticated").generate("test"); - assertEquals("http://test123-res.cloudinary.com/authenticated_images/test/hello", actual); + assertEquals("https://test123-res.cloudinary.com/authenticated_images/test/hello", actual); } @Test public void testSupportUrlSuffixForPrivateImages() { String actual = cloudinary.url().suffix("hello").privateCdn(true).resourceType("image").type("private").generate("test"); - assertEquals("http://test123-res.cloudinary.com/private_images/test/hello", actual); + assertEquals("https://test123-res.cloudinary.com/private_images/test/hello", actual); } @Test public void testSupportUseRootPathForPrivateCdn() { String actual = cloudinary.url().privateCdn(true).useRootPath(true).generate("test"); - assertEquals("http://test123-res.cloudinary.com/test", actual); + assertEquals("https://test123-res.cloudinary.com/test", actual); actual = cloudinary.url().privateCdn(true).transformation(new Transformation().angle(0)).useRootPath(true).generate("test"); - assertEquals("http://test123-res.cloudinary.com/a_0/test", actual); + assertEquals("https://test123-res.cloudinary.com/a_0/test", actual); } @Test public void testSupportUseRootPathTogetherWithUrlSuffixForPrivateCdn() { String actual = cloudinary.url().privateCdn(true).suffix("hello").useRootPath(true).generate("test"); - assertEquals("http://test123-res.cloudinary.com/test/hello", actual); + assertEquals("https://test123-res.cloudinary.com/test/hello", actual); } @@ -452,7 +450,7 @@ public void testNoEmptyTransformation() { public void testHttpEscape() { // should escape http urls String result = cloudinary.url().type("youtube").generate("http://www.youtube.com/watch?v=d9NF2edxy-M"); - assertEquals("http://res.cloudinary.com/test123/image/youtube/http://www.youtube.com/watch%3Fv%3Dd9NF2edxy-M", result); + assertEquals("https://res.cloudinary.com/test123/image/youtube/http://www.youtube.com/watch%3Fv%3Dd9NF2edxy-M", result); } @Test @@ -489,14 +487,14 @@ public void testAngle() { public void testFetchFormat() { // should support format for fetch urls String result = cloudinary.url().format("jpg").type("fetch").generate("http://cloudinary.com/images/old_logo.png"); - assertEquals("http://res.cloudinary.com/test123/image/fetch/f_jpg/http://cloudinary.com/images/old_logo.png", result); + assertEquals("https://res.cloudinary.com/test123/image/fetch/f_jpg/http://cloudinary.com/images/old_logo.png", result); } @Test public void testUseFetchFormat() { // should support use fetch format, adds the format but not an extension String result = cloudinary.url().format("jpg").useFetchFormat(true).generate("old_logo"); - assertEquals("http://res.cloudinary.com/test123/image/upload/f_jpg/old_logo", result); + assertEquals("https://res.cloudinary.com/test123/image/upload/f_jpg/old_logo", result); } @Test @@ -580,24 +578,24 @@ public void testOpacity() { public void testImageTag() { Transformation transformation = new Transformation().width(100).height(101).crop("crop"); String result = cloudinary.url().transformation(transformation).imageTag("test", asMap("alt", "my image")); - assertEquals("my image", result); + assertEquals("my image", result); transformation = new Transformation().width(0.9).height(0.9).crop("crop").responsiveWidth(true); result = cloudinary.url().transformation(transformation).imageTag("test", asMap("alt", "my image")); assertEquals( - "my image", + "my image", result); result = cloudinary.url().transformation(transformation).imageTag("test", asMap("alt", "my image", "class", "extra")); assertEquals( - "my image", + "my image", result); transformation = new Transformation().width("auto").crop("crop"); result = cloudinary.url().transformation(transformation).imageTag("test", asMap("alt", "my image", "responsive_placeholder", "blank")); assertEquals( - "my image", + "my image", result); result = cloudinary.url().transformation(transformation).imageTag("test", asMap("alt", "my image", "responsive_placeholder", "other.gif")); assertEquals( - "my image", + "my image", result); } @@ -614,12 +612,12 @@ public void testClientHints() { assertTrue(testTag.startsWith(" getUrlParameters(URI uri) throws UnsupportedEn @Test public void testUrlCloneConfig() { // verify that secure (from url.config) is cloned as well: - Url url = cloudinary.url().cloudName("cloud").format("frmt").publicId("123").secure(true); + Url url = cloudinary.url().cloudName("cloud").format("frmt").publicId("123"); assertEquals("https://res.cloudinary.com/cloud/image/upload/123.frmt", url.clone().generate()); } diff --git a/cloudinary-core/src/test/java/com/cloudinary/transformation/LayerTest.java b/cloudinary-core/src/test/java/com/cloudinary/transformation/LayerTest.java index d801c4dc..ca230f52 100644 --- a/cloudinary-core/src/test/java/com/cloudinary/transformation/LayerTest.java +++ b/cloudinary-core/src/test/java/com/cloudinary/transformation/LayerTest.java @@ -12,14 +12,14 @@ * Created by amir on 03/11/2015. */ public class LayerTest { - private static final String DEFAULT_ROOT_PATH = "http://res.cloudinary.com/test123/"; + private static final String DEFAULT_ROOT_PATH = "https://res.cloudinary.com/test123/"; private static final String DEFAULT_UPLOAD_PATH = DEFAULT_ROOT_PATH + "image/upload/"; private static final String VIDEO_UPLOAD_PATH = DEFAULT_ROOT_PATH + "video/upload/"; private Cloudinary cloudinary; @Before public void setUp() { - this.cloudinary = new Cloudinary("cloudinary://a:b@test123?load_strategies=false"); + this.cloudinary = new Cloudinary("cloudinary://a:b@test123?load_strategies=false&analytics=false"); } @After @@ -46,7 +46,7 @@ public void testOverlay() { } @Test - public void testUnderlay() { + public void testUnderlay() { Transformation transformation = new Transformation().underlay("text:hello"); String result = cloudinary.url().transformation(transformation).generate("test"); assertEquals(DEFAULT_UPLOAD_PATH + "u_text:hello/test", result); diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java index 99654c4e..8581ca30 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java @@ -41,6 +41,7 @@ abstract public class AbstractUploaderTest extends MockableTest { @BeforeClass public static void setUpClass() throws IOException { Cloudinary cloudinary = new Cloudinary(); + cloudinary.config.analytics = false; if (cloudinary.config.apiSecret == null) { System.err.println("Please setup environment for Upload test to run"); } @@ -89,6 +90,7 @@ public static void tearDownClass() { public void setUp() { System.out.println("Running " + this.getClass().getName() + "." + currentTest.getMethodName()); this.cloudinary = new Cloudinary(); + this.cloudinary.config.analytics = false; assumeNotNull(cloudinary.config.apiSecret); } From 238b54971b153b318b7ffc04823042fd1eb7d745 Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Tue, 30 Jul 2024 17:48:55 +0300 Subject: [PATCH 123/150] Update minimum java version --- java_shared.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java_shared.gradle b/java_shared.gradle index d23a49b4..f7e6e550 100644 --- a/java_shared.gradle +++ b/java_shared.gradle @@ -1,5 +1,5 @@ -sourceCompatibility = 1.7 -targetCompatibility = 1.7 +sourceCompatibility = 1.8 +targetCompatibility = 1.8 javadoc { options.encoding = 'UTF-8' From 232a2e538331c2d4011215dfe61b10fdf2d21b9e Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Tue, 30 Jul 2024 17:52:24 +0300 Subject: [PATCH 124/150] Remove deprecated functions --- .../main/java/com/cloudinary/Cloudinary.java | 5 ----- .../src/main/java/com/cloudinary/Uploader.java | 5 ----- .../transformation/AbstractLayerBuilder.java | 7 ------- .../cloudinary/transformation/Condition.java | 17 ----------------- .../cloudinary/transformation/LayerBuilder.java | 7 ------- .../transformation/SubtitlesLayerBuilder.java | 7 ------- .../transformation/TextLayerBuilder.java | 7 ------- .../com/cloudinary/test/CloudinaryTest.java | 9 +++++---- .../cloudinary/taglib/CloudinaryImageTag.java | 11 ----------- 9 files changed, 5 insertions(+), 70 deletions(-) delete mode 100644 cloudinary-core/src/main/java/com/cloudinary/transformation/AbstractLayerBuilder.java delete mode 100644 cloudinary-core/src/main/java/com/cloudinary/transformation/LayerBuilder.java delete mode 100644 cloudinary-core/src/main/java/com/cloudinary/transformation/SubtitlesLayerBuilder.java delete mode 100644 cloudinary-core/src/main/java/com/cloudinary/transformation/TextLayerBuilder.java diff --git a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java index 24e6f692..3f636d06 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java @@ -401,9 +401,4 @@ private String buildUrl(String base, Map params) throws Unsuppor } return urlBuilder.toString(); } - - @Deprecated - public static Map asMap(Object... values) { - return ObjectUtils.asMap(values); - } } diff --git a/cloudinary-core/src/main/java/com/cloudinary/Uploader.java b/cloudinary-core/src/main/java/com/cloudinary/Uploader.java index d2ae11ea..39b21950 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Uploader.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Uploader.java @@ -263,11 +263,6 @@ public Map explicit(String publicId, Map options) throws IOException { return callApi("explicit", params, options, null); } - @Deprecated - public Map generate_sprite(String tag, Map options) throws IOException { - return generateSprite(tag, options); - } - public Map generateSprite(String tag, Map options) throws IOException { if (options == null) options = Collections.singletonMap("tag", tag); diff --git a/cloudinary-core/src/main/java/com/cloudinary/transformation/AbstractLayerBuilder.java b/cloudinary-core/src/main/java/com/cloudinary/transformation/AbstractLayerBuilder.java deleted file mode 100644 index bcc2cfea..00000000 --- a/cloudinary-core/src/main/java/com/cloudinary/transformation/AbstractLayerBuilder.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.cloudinary.transformation; - -/** - * @deprecated - */ -public abstract class AbstractLayerBuilder extends AbstractLayer { -} diff --git a/cloudinary-core/src/main/java/com/cloudinary/transformation/Condition.java b/cloudinary-core/src/main/java/com/cloudinary/transformation/Condition.java index 35613813..234fd477 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/transformation/Condition.java +++ b/cloudinary-core/src/main/java/com/cloudinary/transformation/Condition.java @@ -65,27 +65,10 @@ public Condition initialDuration(String operator, Object value) { return predicate("idu", operator, value); } - - /** - * @deprecated Use {@link #faceCount(String, Object)} instead - */ - @Deprecated - public Condition faces(String operator, Object value) { - return faceCount(operator, value); - } - public Condition faceCount(String operator, Object value) { return predicate("fc", operator, value); } - /** - * @deprecated Use {@link #pageCount(String, Object)} instead - */ - @Deprecated - public Condition pages(String operator, Object value) { - return pageCount(operator, value); - } - public Condition pageCount(String operator, Object value) { return predicate("pc", operator, value); } diff --git a/cloudinary-core/src/main/java/com/cloudinary/transformation/LayerBuilder.java b/cloudinary-core/src/main/java/com/cloudinary/transformation/LayerBuilder.java deleted file mode 100644 index 5a4ea9df..00000000 --- a/cloudinary-core/src/main/java/com/cloudinary/transformation/LayerBuilder.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.cloudinary.transformation; - -/** - * @deprecated Use {@link Layer} instead - */ -public class LayerBuilder extends Layer { -} diff --git a/cloudinary-core/src/main/java/com/cloudinary/transformation/SubtitlesLayerBuilder.java b/cloudinary-core/src/main/java/com/cloudinary/transformation/SubtitlesLayerBuilder.java deleted file mode 100644 index 22a78625..00000000 --- a/cloudinary-core/src/main/java/com/cloudinary/transformation/SubtitlesLayerBuilder.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.cloudinary.transformation; - -/** - * @deprecated Use {@link SubtitlesLayer} instead - */ -public class SubtitlesLayerBuilder extends SubtitlesLayer { -} diff --git a/cloudinary-core/src/main/java/com/cloudinary/transformation/TextLayerBuilder.java b/cloudinary-core/src/main/java/com/cloudinary/transformation/TextLayerBuilder.java deleted file mode 100644 index 0db485ce..00000000 --- a/cloudinary-core/src/main/java/com/cloudinary/transformation/TextLayerBuilder.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.cloudinary.transformation; - -/** - * @deprecated Use {@link TextLayer} instead - */ -public class TextLayerBuilder extends TextLayer { -} diff --git a/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java b/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java index 0721acae..9e436183 100644 --- a/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java +++ b/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java @@ -146,6 +146,7 @@ public void testSecureDistibution() { public void testSecureAkamai() { // should default to akamai if secure is given with private_cdn and no // secure_distribution + cloudinary.config.secure = true; cloudinary.config.privateCdn = true; String result = cloudinary.url().generate("test"); assertEquals("https://test123-res.cloudinary.com/image/upload/test", result); @@ -155,6 +156,7 @@ public void testSecureAkamai() { public void testSecureNonAkamai() { // should not add cloud_name if private_cdn and secure non akamai // secure_distribution + cloudinary.config.secure = true; cloudinary.config.privateCdn = true; cloudinary.config.secureDistribution = "something.cloudfront.net"; String result = cloudinary.url().generate("test"); @@ -1209,10 +1211,9 @@ public void videoTagWithAuthTokenTest() { .type("upload") .authToken(new AuthToken("123456").duration(300)) .signed(true) -// .videoTag("sample", Cloudinary.asMap( -// "controls", true, -// "loop", true) - .videoTag("sample", asMap("controls", true, + .secure(true) + .videoTag("sample", ObjectUtils.asMap( + "controls", true, "loop", true) ); assert(actualTag.contains("cld_token")); diff --git a/cloudinary-taglib/src/main/java/com/cloudinary/taglib/CloudinaryImageTag.java b/cloudinary-taglib/src/main/java/com/cloudinary/taglib/CloudinaryImageTag.java index d3738278..2de25e3b 100644 --- a/cloudinary-taglib/src/main/java/com/cloudinary/taglib/CloudinaryImageTag.java +++ b/cloudinary-taglib/src/main/java/com/cloudinary/taglib/CloudinaryImageTag.java @@ -72,15 +72,4 @@ public String getExtraClasses() { public void setExtraClasses(String extraClasses) { this.extraClasses = extraClasses; } - - @Deprecated - public void setPublicId(String src) { - this.src = src; - } - - @Deprecated - public String getPublicId() { - return src; - } - } \ No newline at end of file From 178559ba3ea4a7afa2cc18aa3df17dca41ead86b Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Mon, 19 Aug 2024 12:13:04 +0300 Subject: [PATCH 125/150] Add derived next cursor support --- .../src/main/java/com/cloudinary/Api.java | 2 +- .../com/cloudinary/test/AbstractApiTest.java | 25 +++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/cloudinary-core/src/main/java/com/cloudinary/Api.java b/cloudinary-core/src/main/java/com/cloudinary/Api.java index 2899327d..19cd61d8 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Api.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Api.java @@ -200,7 +200,7 @@ public ApiResponse resource(String public_id, Map options) throws Exception { ApiResponse response = callApi(HttpMethod.GET, Arrays.asList("resources", resourceType, type, public_id), ObjectUtils.only(options, "exif", "colors", "faces", "coordinates", "image_metadata", "pages", "phash", "max_results", "quality_analysis", "cinemagraph_analysis", - "accessibility_analysis", "versions", "media_metadata"), options); + "accessibility_analysis", "versions", "media_metadata", "derived_next_cursor"), options); return response; } diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java index dd3802c9..ad89074a 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java @@ -1305,4 +1305,29 @@ public void testDeleteBackedupAsset() throws Exception { assertEquals(deletedVersionIds.get(0), firstAssetVersion); } } + + @Test + public void testAllowDerivedNextCursor() throws Exception { + String publicId = "allowderivednextcursor_" + SUFFIX; + Map options = ObjectUtils.asMap("public_id", publicId, "eager", Arrays.asList( + new Transformation().width(100), + new Transformation().width(101), + new Transformation().width(102) + )); + + try { + cloudinary.uploader().upload(SRC_TEST_IMAGE, options); + ApiResponse res = api.resource(publicId, Collections.singletonMap("max_results", 1)); + String derivedNextCursor = res.get("derived_next_cursor").toString(); + assertNotNull(derivedNextCursor); + + ApiResponse res2 = api.resource(publicId, ObjectUtils.asMap("derived_next_cursor", derivedNextCursor, "max_results", 1)); + String derivedNextCursor2 = res2.get("derived_next_cursor").toString(); + assertNotNull(derivedNextCursor2); + + assertNotEquals(derivedNextCursor, derivedNextCursor2); + } finally { + cloudinary.uploader().destroy(publicId, Collections.singletonMap("invalidate", true)); + } + } } From 5e77cc58a0da6c8fd05c4b13ac7c6ab14fa7c350 Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Mon, 9 Sep 2024 14:04:01 +0300 Subject: [PATCH 126/150] Update http client --- .travis.yml | 5 +- .../src/main/java/com/cloudinary/Api.java | 44 +++- .../main/java/com/cloudinary/Cloudinary.java | 10 +- .../com/cloudinary/provisioning/Account.java | 31 ++- .../strategies/AbstractApiStrategy.java | 33 +-- cloudinary-http42/build.gradle | 114 ---------- .../com/cloudinary/http42/ApiStrategy.java | 142 ------------ .../cloudinary/http42/UploaderStrategy.java | 120 ----------- .../java/com/cloudinary/test/ApiTest.java | 23 -- .../java/com/cloudinary/test/ContextTest.java | 4 - .../com/cloudinary/http43/ApiStrategy.java | 203 ----------------- .../java/com/cloudinary/http43/ApiUtils.java | 53 ----- .../cloudinary/http43/UploaderStrategy.java | 144 ------------- .../com/cloudinary/http43/api/Response.java | 69 ------ .../com/cloudinary/test/AccountApiTest.java | 4 - .../java/com/cloudinary/test/ApiTest.java | 33 --- .../com/cloudinary/test/FoldersApiTest.java | 4 - .../java/com/cloudinary/test/SearchTest.java | 4 - .../test/StreamingProfilesApiTest.java | 7 - .../test/StructuredMetadataTest.java | 4 - .../com/cloudinary/test/UploaderTest.java | 34 --- cloudinary-http44/build.gradle | 113 ---------- .../com/cloudinary/http44/ApiStrategy.java | 204 ------------------ .../java/com/cloudinary/http44/ApiUtils.java | 53 ----- .../cloudinary/http44/UploaderStrategy.java | 145 ------------- .../com/cloudinary/http44/api/Response.java | 69 ------ .../com/cloudinary/test/AccountApiTest.java | 4 - .../java/com/cloudinary/test/ApiTest.java | 32 --- .../java/com/cloudinary/test/ContextTest.java | 5 - .../com/cloudinary/test/FoldersApiTest.java | 4 - .../java/com/cloudinary/test/SearchTest.java | 4 - .../test/StreamingProfilesApiTest.java | 7 - .../test/StructuredMetadataTest.java | 4 - .../com/cloudinary/test/UploaderTest.java | 33 --- cloudinary-http45/build.gradle | 113 ---------- .../com/cloudinary/http45/ApiStrategy.java | 201 ----------------- .../java/com/cloudinary/http45/ApiUtils.java | 53 ----- .../cloudinary/http45/UploaderStrategy.java | 141 ------------ .../com/cloudinary/http45/api/Response.java | 69 ------ .../com/cloudinary/test/AccountApiTest.java | 4 - .../java/com/cloudinary/test/ApiTest.java | 32 --- .../java/com/cloudinary/test/ContextTest.java | 5 - .../com/cloudinary/test/FoldersApiTest.java | 4 - .../java/com/cloudinary/test/SearchTest.java | 4 - .../test/StreamingProfilesApiTest.java | 4 - .../test/StructuredMetadataTest.java | 4 - .../com/cloudinary/test/UploaderTest.java | 34 --- .../build.gradle | 8 +- .../com/cloudinary/http5/ApiStrategy.java | 163 ++++++++++++++ .../java/com/cloudinary/http5/ApiUtils.java | 71 ++++++ .../cloudinary/http5/UploaderStrategy.java | 155 +++++++++++++ .../com/cloudinary/http5}/api/Response.java | 37 ++-- .../com/cloudinary/test/AccountApiTest.java | 0 .../java/com/cloudinary/test/ApiTest.java | 45 ++++ .../java/com/cloudinary/test/ContextTest.java | 0 .../com/cloudinary/test/FoldersApiTest.java | 0 .../java/com/cloudinary/test/SearchTest.java | 0 .../test/StreamingProfilesApiTest.java | 0 .../test/StructuredMetadataTest.java | 0 .../com/cloudinary/test/UploaderTest.java | 2 +- samples/photo_album_gae/pom.xml | 4 +- settings.gradle | 6 +- 62 files changed, 536 insertions(+), 2385 deletions(-) delete mode 100644 cloudinary-http42/build.gradle delete mode 100644 cloudinary-http42/src/main/java/com/cloudinary/http42/ApiStrategy.java delete mode 100644 cloudinary-http42/src/main/java/com/cloudinary/http42/UploaderStrategy.java delete mode 100644 cloudinary-http42/src/test/java/com/cloudinary/test/ApiTest.java delete mode 100644 cloudinary-http42/src/test/java/com/cloudinary/test/ContextTest.java delete mode 100644 cloudinary-http43/src/main/java/com/cloudinary/http43/ApiStrategy.java delete mode 100644 cloudinary-http43/src/main/java/com/cloudinary/http43/ApiUtils.java delete mode 100644 cloudinary-http43/src/main/java/com/cloudinary/http43/UploaderStrategy.java delete mode 100644 cloudinary-http43/src/main/java/com/cloudinary/http43/api/Response.java delete mode 100644 cloudinary-http43/src/test/java/com/cloudinary/test/AccountApiTest.java delete mode 100644 cloudinary-http43/src/test/java/com/cloudinary/test/ApiTest.java delete mode 100644 cloudinary-http43/src/test/java/com/cloudinary/test/FoldersApiTest.java delete mode 100644 cloudinary-http43/src/test/java/com/cloudinary/test/SearchTest.java delete mode 100644 cloudinary-http43/src/test/java/com/cloudinary/test/StreamingProfilesApiTest.java delete mode 100644 cloudinary-http43/src/test/java/com/cloudinary/test/StructuredMetadataTest.java delete mode 100644 cloudinary-http43/src/test/java/com/cloudinary/test/UploaderTest.java delete mode 100644 cloudinary-http44/build.gradle delete mode 100644 cloudinary-http44/src/main/java/com/cloudinary/http44/ApiStrategy.java delete mode 100644 cloudinary-http44/src/main/java/com/cloudinary/http44/ApiUtils.java delete mode 100644 cloudinary-http44/src/main/java/com/cloudinary/http44/UploaderStrategy.java delete mode 100644 cloudinary-http44/src/main/java/com/cloudinary/http44/api/Response.java delete mode 100644 cloudinary-http44/src/test/java/com/cloudinary/test/AccountApiTest.java delete mode 100644 cloudinary-http44/src/test/java/com/cloudinary/test/ApiTest.java delete mode 100644 cloudinary-http44/src/test/java/com/cloudinary/test/ContextTest.java delete mode 100644 cloudinary-http44/src/test/java/com/cloudinary/test/FoldersApiTest.java delete mode 100644 cloudinary-http44/src/test/java/com/cloudinary/test/SearchTest.java delete mode 100644 cloudinary-http44/src/test/java/com/cloudinary/test/StreamingProfilesApiTest.java delete mode 100644 cloudinary-http44/src/test/java/com/cloudinary/test/StructuredMetadataTest.java delete mode 100644 cloudinary-http44/src/test/java/com/cloudinary/test/UploaderTest.java delete mode 100644 cloudinary-http45/build.gradle delete mode 100644 cloudinary-http45/src/main/java/com/cloudinary/http45/ApiStrategy.java delete mode 100644 cloudinary-http45/src/main/java/com/cloudinary/http45/ApiUtils.java delete mode 100644 cloudinary-http45/src/main/java/com/cloudinary/http45/UploaderStrategy.java delete mode 100644 cloudinary-http45/src/main/java/com/cloudinary/http45/api/Response.java delete mode 100644 cloudinary-http45/src/test/java/com/cloudinary/test/AccountApiTest.java delete mode 100644 cloudinary-http45/src/test/java/com/cloudinary/test/ApiTest.java delete mode 100644 cloudinary-http45/src/test/java/com/cloudinary/test/ContextTest.java delete mode 100644 cloudinary-http45/src/test/java/com/cloudinary/test/FoldersApiTest.java delete mode 100644 cloudinary-http45/src/test/java/com/cloudinary/test/SearchTest.java delete mode 100644 cloudinary-http45/src/test/java/com/cloudinary/test/StreamingProfilesApiTest.java delete mode 100644 cloudinary-http45/src/test/java/com/cloudinary/test/StructuredMetadataTest.java delete mode 100644 cloudinary-http45/src/test/java/com/cloudinary/test/UploaderTest.java rename {cloudinary-http43 => cloudinary-http5}/build.gradle (92%) create mode 100644 cloudinary-http5/src/main/java/com/cloudinary/http5/ApiStrategy.java create mode 100644 cloudinary-http5/src/main/java/com/cloudinary/http5/ApiUtils.java create mode 100644 cloudinary-http5/src/main/java/com/cloudinary/http5/UploaderStrategy.java rename {cloudinary-http42/src/main/java/com/cloudinary/http42 => cloudinary-http5/src/main/java/com/cloudinary/http5}/api/Response.java (72%) rename {cloudinary-http42 => cloudinary-http5}/src/test/java/com/cloudinary/test/AccountApiTest.java (100%) create mode 100644 cloudinary-http5/src/test/java/com/cloudinary/test/ApiTest.java rename {cloudinary-http43 => cloudinary-http5}/src/test/java/com/cloudinary/test/ContextTest.java (100%) rename {cloudinary-http42 => cloudinary-http5}/src/test/java/com/cloudinary/test/FoldersApiTest.java (100%) rename {cloudinary-http42 => cloudinary-http5}/src/test/java/com/cloudinary/test/SearchTest.java (100%) rename {cloudinary-http42 => cloudinary-http5}/src/test/java/com/cloudinary/test/StreamingProfilesApiTest.java (100%) rename {cloudinary-http42 => cloudinary-http5}/src/test/java/com/cloudinary/test/StructuredMetadataTest.java (100%) rename {cloudinary-http42 => cloudinary-http5}/src/test/java/com/cloudinary/test/UploaderTest.java (97%) diff --git a/.travis.yml b/.travis.yml index 510d55ae..8a1fec22 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,10 +18,7 @@ jdk: env: - MODULE=core - - MODULE=http42 - - MODULE=http43 - - MODULE=http44 - - MODULE=http45 + - MODULE=http5 branches: except: diff --git a/cloudinary-core/src/main/java/com/cloudinary/Api.java b/cloudinary-core/src/main/java/com/cloudinary/Api.java index 19cd61d8..9dbacde9 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Api.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Api.java @@ -9,6 +9,7 @@ import com.cloudinary.metadata.MetadataDataSource; import com.cloudinary.metadata.MetadataRule; import com.cloudinary.strategies.AbstractApiStrategy; +import com.cloudinary.utils.Base64Coder; import com.cloudinary.utils.ObjectUtils; import com.cloudinary.utils.StringUtils; import org.cloudinary.json.JSONArray; @@ -40,7 +41,19 @@ public enum HttpMethod {GET, POST, PUT, DELETE;} private AbstractApiStrategy strategy; protected ApiResponse callApi(HttpMethod method, Iterable uri, Map params, Map options) throws Exception { - return this.strategy.callApi(method, uri, params, options); + if (options == null) + options = ObjectUtils.emptyMap(); + + String apiKey = ObjectUtils.asString(options.get("api_key"), this.cloudinary.config.apiKey); + String apiSecret = ObjectUtils.asString(options.get("api_secret"), this.cloudinary.config.apiSecret); + String oauthToken = ObjectUtils.asString(options.get("oauth_token"), this.cloudinary.config.oauthToken); + + validateAuthorization(apiKey, apiSecret, oauthToken); + + + String authorizationHeader = getAuthorizationHeaderValue(apiKey, apiSecret, oauthToken); + String apiUrl = createApiUrl(uri, options); + return this.strategy.callApi(method, apiUrl, params, options, authorizationHeader); } public Api(Cloudinary cloudinary, AbstractApiStrategy strategy) { @@ -871,4 +884,33 @@ public ApiResponse deleteBackedUpAssets(String assetId, String[] versionIds, Map } return result; } + + protected void validateAuthorization(String apiKey, String apiSecret, String oauthToken) { + if (oauthToken == null) { + if (apiKey == null) throw new IllegalArgumentException("Must supply api_key"); + if (apiSecret == null) throw new IllegalArgumentException("Must supply api_secret"); + } + } + + protected String getAuthorizationHeaderValue(String apiKey, String apiSecret, String oauthToken) { + if (oauthToken != null){ + return "Bearer " + oauthToken; + } else { + return "Basic " + Base64Coder.encodeString(apiKey + ":" + apiSecret); + } + } + + protected String createApiUrl (Iterable uri, Map options){ + String version = ObjectUtils.asString(options.get("api_version"), "v1_1"); + String prefix = ObjectUtils.asString(options.get("upload_prefix"), ObjectUtils.asString(this.cloudinary.config.uploadPrefix, "https://api.cloudinary.com")); + String cloudName = ObjectUtils.asString(options.get("cloud_name"), this.cloudinary.config.cloudName); + if (cloudName == null) throw new IllegalArgumentException("Must supply cloud_name"); + String apiUrl = StringUtils.join(Arrays.asList(prefix, version, cloudName), "/"); + for (String component : uri) { + component = SmartUrlEncoder.encode(component); + apiUrl = apiUrl + "/" + component; + + } + return apiUrl; + } } diff --git a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java index 3f636d06..27b347ac 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java @@ -22,16 +22,10 @@ public class Cloudinary { private static List UPLOAD_STRATEGIES = new ArrayList(Arrays.asList( "com.cloudinary.android.UploaderStrategy", - "com.cloudinary.http42.UploaderStrategy", - "com.cloudinary.http43.UploaderStrategy", - "com.cloudinary.http44.UploaderStrategy", - "com.cloudinary.http45.UploaderStrategy")); + "com.cloudinary.http5.UploaderStrategy")); public static List API_STRATEGIES = new ArrayList(Arrays.asList( "com.cloudinary.android.ApiStrategy", - "com.cloudinary.http42.ApiStrategy", - "com.cloudinary.http43.ApiStrategy", - "com.cloudinary.http44.ApiStrategy", - "com.cloudinary.http45.ApiStrategy")); + "com.cloudinary.http5.ApiStrategy")); public final static String CF_SHARED_CDN = "d3jpl91pxevbkh.cloudfront.net"; public final static String OLD_AKAMAI_SHARED_CDN = "cloudinary-a.akamaihd.net"; diff --git a/cloudinary-core/src/main/java/com/cloudinary/provisioning/Account.java b/cloudinary-core/src/main/java/com/cloudinary/provisioning/Account.java index c149e5dc..1c545345 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/provisioning/Account.java +++ b/cloudinary-core/src/main/java/com/cloudinary/provisioning/Account.java @@ -4,7 +4,10 @@ import com.cloudinary.Cloudinary; import com.cloudinary.Util; import com.cloudinary.api.ApiResponse; +import com.cloudinary.utils.Base64Coder; import com.cloudinary.utils.ObjectUtils; +import com.cloudinary.utils.StringUtils; + import java.util.*; /** @@ -76,7 +79,25 @@ private ApiResponse callAccountApi(Api.HttpMethod method, List uri, Map< } Util.clearEmpty(params); - return api.getStrategy().callAccountApi(method, uri, params, options); + + if (options == null) { + options = ObjectUtils.emptyMap(); + } + + String prefix = ObjectUtils.asString(options.get("upload_prefix"), "https://api.cloudinary.com"); + String apiKey = ObjectUtils.asString(options.get("provisioning_api_key")); + if (apiKey == null) throw new IllegalArgumentException("Must supply provisioning_api_key"); + String apiSecret = ObjectUtils.asString(options.get("provisioning_api_secret")); + if (apiSecret == null) throw new IllegalArgumentException("Must supply provisioning_api_secret"); + + String apiUrl = StringUtils.join(Arrays.asList(prefix, "v1_1"), "/"); + for (String component : uri) { + apiUrl = apiUrl + "/" + component; + } + + String authorizationHeader = getAuthorizationHeaderValue(apiKey, apiSecret, null); + + return api.getStrategy().callAccountApi(method, apiUrl, params, options, authorizationHeader); } /** @@ -707,4 +728,12 @@ private Map verifyOptions(Map options) { return options; } + + protected String getAuthorizationHeaderValue(String apiKey, String apiSecret, String oauthToken) { + if (oauthToken != null){ + return "Bearer " + oauthToken; + } else { + return "Basic " + Base64Coder.encodeString(apiKey + ":" + apiSecret); + } + } } diff --git a/cloudinary-core/src/main/java/com/cloudinary/strategies/AbstractApiStrategy.java b/cloudinary-core/src/main/java/com/cloudinary/strategies/AbstractApiStrategy.java index 2d5a514d..8878bf2c 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/strategies/AbstractApiStrategy.java +++ b/cloudinary-core/src/main/java/com/cloudinary/strategies/AbstractApiStrategy.java @@ -18,37 +18,8 @@ public void init(Api api) { this.api = api; } - protected String createApiUrl (Iterable uri, Map options){ - String version = ObjectUtils.asString(options.get("api_version"), "v1_1"); - String prefix = ObjectUtils.asString(options.get("upload_prefix"), ObjectUtils.asString(this.api.cloudinary.config.uploadPrefix, "https://api.cloudinary.com")); - String cloudName = ObjectUtils.asString(options.get("cloud_name"), this.api.cloudinary.config.cloudName); - if (cloudName == null) throw new IllegalArgumentException("Must supply cloud_name"); - String apiUrl = StringUtils.join(Arrays.asList(prefix, version, cloudName), "/"); - for (String component : uri) { - component = SmartUrlEncoder.encode(component); - apiUrl = apiUrl + "/" + component; - - } - return apiUrl; - } - @SuppressWarnings("rawtypes") - public abstract ApiResponse callApi(HttpMethod method, Iterable uri, Map params, Map options) throws Exception; - - public abstract ApiResponse callAccountApi(HttpMethod method, Iterable uri, Map params, Map options) throws Exception; + public abstract ApiResponse callApi(HttpMethod method, String apiUrl, Map params, Map options, String authorizationHeader) throws Exception; - protected String getAuthorizationHeaderValue(String apiKey, String apiSecret, String oauthToken) { - if (oauthToken != null){ - return "Bearer " + oauthToken; - } else { - return "Basic " + Base64Coder.encodeString(apiKey + ":" + apiSecret); - } - } - - protected void validateAuthorization(String apiKey, String apiSecret, String oauthToken) { - if (oauthToken == null) { - if (apiKey == null) throw new IllegalArgumentException("Must supply api_key"); - if (apiSecret == null) throw new IllegalArgumentException("Must supply api_secret"); - } - } + public abstract ApiResponse callAccountApi(HttpMethod method, String apiUrl, Map params, Map options, String authorizationHeader) throws Exception; } diff --git a/cloudinary-http42/build.gradle b/cloudinary-http42/build.gradle deleted file mode 100644 index 7c94214b..00000000 --- a/cloudinary-http42/build.gradle +++ /dev/null @@ -1,114 +0,0 @@ -plugins { - id 'java-library' - id 'signing' - id 'maven-publish' - id 'io.codearte.nexus-staging' version '0.21.1' -} - -apply from: "../java_shared.gradle" - -task ciTest( type: Test ) { - useJUnit { - excludeCategories 'com.cloudinary.test.TimeoutTest' - if (System.getProperty("CLOUDINARY_ACCOUNT_URL") == "") { - exclude '**/AccountApiTest.class' - } - } -} - -dependencies { - compile project(':cloudinary-core') - compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.1' - compile group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.2.1' - compile group: 'org.apache.httpcomponents', name: 'httpcore', version: '4.2.1' - compile group: 'org.apache.httpcomponents', name: 'httpmime', version: '4.2.1' - testCompile project(':cloudinary-test-common') - testCompile group: 'org.hamcrest', name: 'java-hamcrest', version: '2.0.0.0' - testCompile group: 'pl.pragmatists', name: 'JUnitParams', version: '1.0.5' - testCompile group: 'junit', name: 'junit', version: '4.12' -} - -if (hasProperty("ossrhPassword")) { - - signing { - sign configurations.archives - } - - nexusStaging { - packageGroup = group - username = project.hasProperty("ossrhUsername") ? project.ext["ossrhUsername"] : "" - password = project.hasProperty("ossrhPassword") ? project.ext["ossrhPassword"] : "" - } - - publishing { - publications { - mavenJava(MavenPublication) { - from components.java - artifact sourcesJar - artifact javadocJar - pom { - name = 'Cloudinary Apache HTTP 4.2 Library' - packaging = 'jar' - groupId = publishGroupId - artifactId = 'cloudinary-http42' - description = publishDescription - url = githubUrl - licenses { - license { - name = licenseName - url = licenseUrl - } - } - - developers { - developer { - id = developerId - name = developerName - email = developerEmail - } - } - scm { - connection = scmConnection - developerConnection = scmDeveloperConnection - url = scmUrl - } - } - - pom.withXml { - def pomFile = file("${project.buildDir}/generated-pom.xml") - writeTo(pomFile) - def pomAscFile = signing.sign(pomFile).signatureFiles[0] - artifact(pomAscFile) { - classifier = null - extension = 'pom.asc' - } - } - - // create the signed artifacts - project.tasks.signArchives.signatureFiles.each { - artifact(it) { - def matcher = it.file =~ /-(sources|javadoc)\.jar\.asc$/ - if (matcher.find()) { - classifier = matcher.group(1) - } else { - classifier = null - } - extension = 'jar.asc' - } - } - } - } - - model { - tasks.generatePomFileForMavenJavaPublication { - destination = file("$buildDir/generated-pom.xml") - } - tasks.publishMavenJavaPublicationToMavenLocal { - dependsOn project.tasks.signArchives - } - tasks.publishMavenJavaPublicationToSonatypeRepository { - dependsOn project.tasks.signArchives - } - } - } -} diff --git a/cloudinary-http42/src/main/java/com/cloudinary/http42/ApiStrategy.java b/cloudinary-http42/src/main/java/com/cloudinary/http42/ApiStrategy.java deleted file mode 100644 index 4a90ed86..00000000 --- a/cloudinary-http42/src/main/java/com/cloudinary/http42/ApiStrategy.java +++ /dev/null @@ -1,142 +0,0 @@ -package com.cloudinary.http42; - -import com.cloudinary.Api; -import com.cloudinary.Api.HttpMethod; -import com.cloudinary.Cloudinary; -import com.cloudinary.api.ApiResponse; -import com.cloudinary.api.exceptions.GeneralError; -import com.cloudinary.http42.api.Response; -import com.cloudinary.strategies.AbstractApiStrategy; -import com.cloudinary.utils.Base64Coder; -import com.cloudinary.utils.ObjectUtils; -import com.cloudinary.utils.StringUtils; -import org.apache.http.HttpResponse; -import org.apache.http.client.methods.*; -import org.apache.http.client.utils.URIBuilder; -import org.apache.http.conn.ClientConnectionManager; -import org.apache.http.entity.ContentType; -import org.apache.http.entity.StringEntity; -import org.apache.http.impl.client.DefaultHttpClient; -import org.apache.http.params.HttpConnectionParams; -import org.apache.http.params.HttpParams; -import org.cloudinary.json.JSONException; -import org.cloudinary.json.JSONObject; - -import java.io.InputStream; -import java.lang.reflect.Constructor; -import java.net.URI; -import java.util.Arrays; -import java.util.Map; - -public class ApiStrategy extends AbstractApiStrategy { - - @SuppressWarnings({"rawtypes", "unchecked"}) - public ApiResponse callApi(HttpMethod method, Iterable uri, Map params, Map options) throws Exception { - if (options == null) options = ObjectUtils.emptyMap(); - - String apiKey = ObjectUtils.asString(options.get("api_key"), this.api.cloudinary.config.apiKey); - String apiSecret = ObjectUtils.asString(options.get("api_secret"), this.api.cloudinary.config.apiSecret); - String oauthToken = ObjectUtils.asString(options.get("oauth_token"), this.api.cloudinary.config.oauthToken); - String contentType = ObjectUtils.asString(options.get("content_type"), "urlencoded"); - int timeout = ObjectUtils.asInteger(options.get("timeout"), this.api.cloudinary.config.timeout); - validateAuthorization(apiKey, apiSecret, oauthToken); - - String apiUrl = createApiUrl(uri, options); - - return getApiResponse(method, params, apiKey, apiSecret, oauthToken, contentType, timeout, apiUrl); - } - - @Override - public ApiResponse callAccountApi(HttpMethod method, Iterable uri, Map params, Map options) throws Exception { - String prefix = ObjectUtils.asString(options.get("upload_prefix"), "https://api.cloudinary.com"); - String apiKey = ObjectUtils.asString(options.get("provisioning_api_key")); - if (apiKey == null) throw new IllegalArgumentException("Must supply provisioning_api_key"); - String apiSecret = ObjectUtils.asString(options.get("provisioning_api_secret")); - if (apiSecret == null) throw new IllegalArgumentException("Must supply provisioning_api_secret"); - String contentType = ObjectUtils.asString(options.get("content_type"), "urlencoded"); - int timeout = ObjectUtils.asInteger(options.get("timeout"), this.api.cloudinary.config.timeout); - - String apiUrl = StringUtils.join(Arrays.asList(prefix, "v1_1"), "/"); - for (String component : uri) { - apiUrl = apiUrl + "/" + component; - } - - return getApiResponse(method, params, apiKey, apiSecret, null, contentType, timeout, apiUrl); - } - - private ApiResponse getApiResponse(HttpMethod method, Map params, String apiKey, String apiSecret, String oauthToken, String contentType, int timeout, String apiUrl) throws Exception { - URIBuilder apiUrlBuilder = new URIBuilder(apiUrl); - if (!contentType.equals("json")) { - for (Map.Entry param : params.entrySet()) { - if (param.getValue() instanceof Iterable) { - for (String single : (Iterable) param.getValue()) { - apiUrlBuilder.addParameter(param.getKey() + "[]", single); - } - } else { - apiUrlBuilder.addParameter(param.getKey(), ObjectUtils.asString(param.getValue())); - } - } - } - - ClientConnectionManager connectionManager = (ClientConnectionManager) this.api.cloudinary.config.properties.get("connectionManager"); - - DefaultHttpClient client = new DefaultHttpClient(connectionManager); - if (timeout > 0) { - HttpParams httpParams = client.getParams(); - HttpConnectionParams.setConnectionTimeout(httpParams, timeout); - HttpConnectionParams.setSoTimeout(httpParams, timeout); - } - - URI apiUri = apiUrlBuilder.build(); - HttpUriRequest request = null; - switch (method) { - case GET: - request = new HttpGet(apiUri); - break; - case PUT: - request = new HttpPut(apiUri); - break; - case POST: - request = new HttpPost(apiUri); - break; - case DELETE: - request = new HttpDelete(apiUri); - break; - } - request.setHeader("Authorization", getAuthorizationHeaderValue(apiKey, apiSecret, oauthToken)); - request.setHeader("User-Agent", this.api.cloudinary.getUserAgent() + " ApacheHTTPComponents/4.2"); - if (contentType.equals("json")) { - JSONObject asJSON = ObjectUtils.toJSON(params); - StringEntity requestEntity = new StringEntity(asJSON.toString(), ContentType.APPLICATION_JSON); - ((HttpEntityEnclosingRequestBase) request).setEntity(requestEntity); - } - - HttpResponse response = client.execute(request); - - int code = response.getStatusLine().getStatusCode(); - InputStream responseStream = response.getEntity().getContent(); - String responseData = StringUtils.read(responseStream); - - Class exceptionClass = Api.CLOUDINARY_API_ERROR_CLASSES.get(code); - if (code != 200 && exceptionClass == null) { - throw new GeneralError("Server returned unexpected status code - " + code + " - " + responseData); - } - Map result; - - try { - JSONObject responseJSON = new JSONObject(responseData); - result = ObjectUtils.toMap(responseJSON); - } catch (JSONException e) { - throw new RuntimeException("Invalid JSON response from server " + e.getMessage()); - } - - if (code == 200) { - return new Response(response, result); - } else { - String message = (String) ((Map) result.get("error")).get("message"); - Constructor exceptionConstructor = exceptionClass.getConstructor(String.class); - throw exceptionConstructor.newInstance(message); - } - } - -} diff --git a/cloudinary-http42/src/main/java/com/cloudinary/http42/UploaderStrategy.java b/cloudinary-http42/src/main/java/com/cloudinary/http42/UploaderStrategy.java deleted file mode 100644 index 0e38365d..00000000 --- a/cloudinary-http42/src/main/java/com/cloudinary/http42/UploaderStrategy.java +++ /dev/null @@ -1,120 +0,0 @@ -package com.cloudinary.http42; - -import com.cloudinary.Cloudinary; -import com.cloudinary.ProgressCallback; -import com.cloudinary.Util; -import com.cloudinary.strategies.AbstractUploaderStrategy; -import com.cloudinary.utils.ObjectUtils; -import com.cloudinary.utils.StringUtils; -import org.apache.http.HttpHost; -import org.apache.http.HttpResponse; -import org.apache.http.client.HttpClient; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.conn.ClientConnectionManager; -import org.apache.http.conn.params.ConnRoutePNames; -import org.apache.http.entity.mime.HttpMultipartMode; -import org.apache.http.entity.mime.MultipartEntity; -import org.apache.http.entity.mime.content.ByteArrayBody; -import org.apache.http.entity.mime.content.FileBody; -import org.apache.http.entity.mime.content.StringBody; -import org.apache.http.impl.client.DefaultHttpClient; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.util.Collection; -import java.util.Map; - -public class UploaderStrategy extends AbstractUploaderStrategy { - - @SuppressWarnings({"rawtypes", "unchecked"}) - @Override - public Map callApi(String action, Map params, Map options, Object file, ProgressCallback progressCallback) throws IOException { - if (progressCallback != null){ - throw new IllegalArgumentException("Progress callback is not supported"); - } - - // initialize options if passed as null - if (options == null) { - options = ObjectUtils.emptyMap(); - } - - boolean returnError = ObjectUtils.asBoolean(options.get("return_error"), false); - - if (requiresSigning(action, options)) { - uploader.signRequestParams(params, options); - } else { - Util.clearEmpty(params); - } - - String apiUrl = buildUploadUrl(action, options); - - ClientConnectionManager connectionManager = (ClientConnectionManager) this.uploader.cloudinary().config.properties.get("connectionManager"); - HttpClient client = new DefaultHttpClient(connectionManager); - - // If the configuration specifies a proxy then apply it to the client - if (uploader.cloudinary().config.proxyHost != null && uploader.cloudinary().config.proxyPort != 0) { - HttpHost proxy = new HttpHost(uploader.cloudinary().config.proxyHost, uploader.cloudinary().config.proxyPort); - client.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy); - } - - HttpPost postMethod = new HttpPost(apiUrl); - postMethod.setHeader("User-Agent", this.cloudinary().getUserAgent() + " ApacheHTTPComponents/4.2"); - - Map extraHeaders = (Map) options.get("extra_headers"); - if (extraHeaders != null) { - for (Map.Entry header : extraHeaders.entrySet()) { - postMethod.setHeader(header.getKey(), header.getValue()); - } - } - - Charset utf8 = Charset.forName("UTF-8"); - - MultipartEntity multipart = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE, null, StandardCharsets.UTF_8); - // Remove blank parameters - for (Map.Entry param : params.entrySet()) { - if (param.getValue() instanceof Collection) { - for (Object value : (Collection) param.getValue()) { - multipart.addPart(param.getKey() + "[]", new StringBody(ObjectUtils.asString(value), utf8)); - } - } else { - String value = param.getValue().toString(); - if (StringUtils.isNotBlank(value)) { - multipart.addPart(param.getKey(), new StringBody(value, utf8)); - } - } - } - if(file instanceof String && !(StringUtils.isRemoteUrl((String)file))){ - File _file = new File((String) file); - if (!_file.isFile() && !_file.canRead()) { - throw new IOException("File not found or unreadable: " + file); - } - file = _file; - } - - String filename = (String) options.get("filename"); - if (file instanceof File) { - multipart.addPart("file", new FileBody((File) file, filename, "application/octet-stream", null)); - } else if (file instanceof String) { - multipart.addPart("file", new StringBody((String) file, utf8)); - } else if (file instanceof byte[]) { - if (filename == null) filename = "file"; - multipart.addPart("file", new ByteArrayBody((byte[]) file, filename)); - } else if (file == null) { - // no-problem - } else { - throw new IOException("Unrecognized file parameter " + file); - } - postMethod.setEntity(multipart); - - HttpResponse response = client.execute(postMethod); - int code = response.getStatusLine().getStatusCode(); - InputStream responseStream = response.getEntity().getContent(); - String responseData = StringUtils.read(responseStream); - - return processResponse(returnError, code, responseData); - } - -} diff --git a/cloudinary-http42/src/test/java/com/cloudinary/test/ApiTest.java b/cloudinary-http42/src/test/java/com/cloudinary/test/ApiTest.java deleted file mode 100644 index b3fa3556..00000000 --- a/cloudinary-http42/src/test/java/com/cloudinary/test/ApiTest.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.cloudinary.test; - -import org.apache.http.conn.ConnectTimeoutException; -import org.junit.Test; -import org.junit.experimental.categories.Category; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -public class ApiTest extends AbstractApiTest { - @Category(TimeoutTest.class) - @Test(expected = ConnectTimeoutException.class) - public void testTimeoutException() throws Exception { - // should allow listing resources - Map options = new HashMap(); - options.put("timeout", Integer.valueOf(1)); - - Map result = api.resources(options); - Map resource = findByAttr((List) result.get("resources"), "public_id", "api_test"); - - } -} diff --git a/cloudinary-http42/src/test/java/com/cloudinary/test/ContextTest.java b/cloudinary-http42/src/test/java/com/cloudinary/test/ContextTest.java deleted file mode 100644 index 1c126299..00000000 --- a/cloudinary-http42/src/test/java/com/cloudinary/test/ContextTest.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.cloudinary.test; - -public class ContextTest extends AbstractContextTest { -} diff --git a/cloudinary-http43/src/main/java/com/cloudinary/http43/ApiStrategy.java b/cloudinary-http43/src/main/java/com/cloudinary/http43/ApiStrategy.java deleted file mode 100644 index 0d619e11..00000000 --- a/cloudinary-http43/src/main/java/com/cloudinary/http43/ApiStrategy.java +++ /dev/null @@ -1,203 +0,0 @@ -package com.cloudinary.http43; - -import com.cloudinary.Api; -import com.cloudinary.Api.HttpMethod; -import com.cloudinary.Cloudinary; -import com.cloudinary.api.ApiResponse; -import com.cloudinary.api.exceptions.GeneralError; -import com.cloudinary.http43.api.Response; -import com.cloudinary.utils.Base64Coder; -import com.cloudinary.utils.ObjectUtils; -import com.cloudinary.utils.StringUtils; -import org.apache.http.Consts; -import org.apache.http.HttpEntity; -import org.apache.http.HttpHost; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.entity.UrlEncodedFormEntity; -import org.apache.http.client.methods.*; -import org.apache.http.client.utils.URIBuilder; -import org.apache.http.conn.HttpClientConnectionManager; -import org.apache.http.entity.ContentType; -import org.apache.http.entity.StringEntity; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClientBuilder; -import org.apache.http.impl.client.HttpClients; -import org.apache.http.util.EntityUtils; -import org.cloudinary.json.JSONException; -import org.cloudinary.json.JSONObject; - -import java.io.InputStream; -import java.io.UnsupportedEncodingException; -import java.lang.reflect.Constructor; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; - -import static com.cloudinary.http43.ApiUtils.prepareParams; -import static com.cloudinary.http43.ApiUtils.setTimeouts; - -public class ApiStrategy extends com.cloudinary.strategies.AbstractApiStrategy { - - private CloseableHttpClient client = null; - - @Override - public void init(Api api) { - super.init(api); - - HttpClientBuilder clientBuilder = HttpClients.custom(); - clientBuilder.useSystemProperties().setUserAgent(this.api.cloudinary.getUserAgent() + " ApacheHTTPComponents/4.3"); - - // If the configuration specifies a proxy then apply it to the client - if (api.cloudinary.config.proxyHost != null && api.cloudinary.config.proxyPort != 0) { - HttpHost proxy = new HttpHost(api.cloudinary.config.proxyHost, api.cloudinary.config.proxyPort); - clientBuilder.setProxy(proxy); - } - - HttpClientConnectionManager connectionManager = (HttpClientConnectionManager) api.cloudinary.config.properties.get("connectionManager"); - if (connectionManager != null) { - clientBuilder.setConnectionManager(connectionManager); - } - - int timeout = this.api.cloudinary.config.timeout; - if (timeout > 0) { - RequestConfig config = RequestConfig.custom() - .setSocketTimeout(timeout * 1000) - .setConnectTimeout(timeout * 1000) - .build(); - clientBuilder.setDefaultRequestConfig(config); - } - - this.client = clientBuilder.build(); - } - - @SuppressWarnings({"rawtypes", "unchecked"}) - public ApiResponse callApi(HttpMethod method, Iterable uri, Map params, Map options) throws Exception { - if (options == null) - options = ObjectUtils.emptyMap(); - - String apiKey = ObjectUtils.asString(options.get("api_key"), this.api.cloudinary.config.apiKey); - String apiSecret = ObjectUtils.asString(options.get("api_secret"), this.api.cloudinary.config.apiSecret); - String oauthToken = ObjectUtils.asString(options.get("oauth_token"), this.api.cloudinary.config.oauthToken); - - validateAuthorization(apiKey, apiSecret, oauthToken); - - String apiUrl = createApiUrl(uri, options); - HttpUriRequest request = prepareRequest(method, apiUrl, params, options); - - request.setHeader("Authorization", getAuthorizationHeaderValue(apiKey, apiSecret, oauthToken)); - - return getApiResponse(request); - } - - private ApiResponse getApiResponse(HttpUriRequest request) throws Exception { - String responseData = null; - int code = 0; - CloseableHttpResponse response = client.execute(request); - try { - code = response.getStatusLine().getStatusCode(); - final HttpEntity entity = response.getEntity(); - responseData = StringUtils.read(entity.getContent()); - EntityUtils.consume(entity); - } finally { - response.close(); - } - - Class exceptionClass = Api.CLOUDINARY_API_ERROR_CLASSES.get(code); - if (code != 200 && exceptionClass == null) { - throw new GeneralError("Server returned unexpected status code - " + code + " - " + responseData); - } - Map result; - - try { - JSONObject responseJSON = new JSONObject(responseData); - result = ObjectUtils.toMap(responseJSON); - } catch (JSONException e) { - throw new RuntimeException("Invalid JSON response from server " + e.getMessage()); - } - - if (code == 200) { - return new Response(response, result); - } else { - String message = (String) ((Map) result.get("error")).get("message"); - Constructor exceptionConstructor = exceptionClass.getConstructor(String.class); - throw exceptionConstructor.newInstance(message); - } - } - - @Override - public ApiResponse callAccountApi(HttpMethod method, Iterable uri, Map params, Map options) throws Exception { - if (options == null) - options = ObjectUtils.emptyMap(); - - String prefix = ObjectUtils.asString(options.get("upload_prefix"), "https://api.cloudinary.com"); - String apiKey = ObjectUtils.asString(options.get("provisioning_api_key")); - if (apiKey == null) throw new IllegalArgumentException("Must supply provisioning_api_key"); - String apiSecret = ObjectUtils.asString(options.get("provisioning_api_secret")); - if (apiSecret == null) throw new IllegalArgumentException("Must supply provisioning_api_secret"); - - String apiUrl = StringUtils.join(Arrays.asList(prefix, "v1_1"), "/"); - for (String component : uri) { - apiUrl = apiUrl + "/" + component; - } - - HttpUriRequest request = prepareRequest(method, apiUrl, params, options); - - request.setHeader("Authorization", "Basic " + Base64Coder.encodeString(apiKey + ":" + apiSecret)); - - return getApiResponse(request); - } - - /** - * Prepare a request with the URL and parameters based on the HTTP method used - * - * @param method the HTTP method: GET, PUT, POST, DELETE - * @param apiUrl the cloudinary API URI - * @param params the parameters to pass to the server - * @return an HTTP request - * @throws URISyntaxException - * @throws UnsupportedEncodingException - */ - private HttpUriRequest prepareRequest(HttpMethod method, String apiUrl, Map params, Map options) throws URISyntaxException, UnsupportedEncodingException { - URI apiUri; - HttpRequestBase request; - - String contentType = ObjectUtils.asString(options.get("content_type"), "urlencoded"); - URIBuilder apiUrlBuilder = new URIBuilder(apiUrl); - HashMap unboxedParams = new HashMap(params); - - if (method == HttpMethod.GET) { - apiUrlBuilder.setParameters(prepareParams(params)); - apiUri = apiUrlBuilder.build(); - request = new HttpGet(apiUri); - } else { - apiUri = apiUrlBuilder.build(); - switch (method) { - case PUT: - request = new HttpPut(apiUri); - break; - case DELETE: //uses HttpPost instead of HttpDelete - unboxedParams.put("_method","delete"); - //continue with POST - case POST: - request = new HttpPost(apiUri); - break; - default: - throw new IllegalArgumentException("Unknown HTTP method"); - } - if (contentType.equals("json")) { - JSONObject asJSON = ObjectUtils.toJSON(unboxedParams); - StringEntity requestEntity = new StringEntity(asJSON.toString(), ContentType.APPLICATION_JSON); - ((HttpEntityEnclosingRequestBase) request).setEntity(requestEntity); - } else { - ((HttpEntityEnclosingRequestBase) request).setEntity(new UrlEncodedFormEntity(prepareParams(unboxedParams), Consts.UTF_8)); - } - } - - setTimeouts(request, options); - return request; - } - - -} diff --git a/cloudinary-http43/src/main/java/com/cloudinary/http43/ApiUtils.java b/cloudinary-http43/src/main/java/com/cloudinary/http43/ApiUtils.java deleted file mode 100644 index 0356934b..00000000 --- a/cloudinary-http43/src/main/java/com/cloudinary/http43/ApiUtils.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.cloudinary.http43; - -import com.cloudinary.utils.ObjectUtils; -import org.apache.http.NameValuePair; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.methods.HttpRequestBase; -import org.apache.http.message.BasicNameValuePair; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -public class ApiUtils { - - public static void setTimeouts(HttpRequestBase request, Map options) { - RequestConfig config= request.getConfig(); - final RequestConfig.Builder builder; - if (config != null) { - builder = RequestConfig.copy(config); - } else { - builder = RequestConfig.custom(); - } - Integer timeout = (Integer) options.get("timeout"); - if(timeout != null) { - builder.setSocketTimeout(timeout); - } - Integer connectionRequestTimeout = (Integer) options.get("connection_request_timeout"); - if(connectionRequestTimeout != null) { - builder.setConnectionRequestTimeout(connectionRequestTimeout); - } - Integer connectTimeout = (Integer) options.get("connect_timeout"); - if(connectTimeout != null) { - builder.setConnectTimeout(connectTimeout); - } - request.setConfig(builder.build()); - } - - static List prepareParams(Map params) { - List requestParams = new ArrayList(params.size()); - for (Map.Entry param : params.entrySet()) { - if (param.getValue() instanceof Iterable) { - for (Object single : (Iterable) param.getValue()) { - requestParams.add(new BasicNameValuePair(param.getKey() + "[]", ObjectUtils.asString(single))); - } - } else { - requestParams.add(new BasicNameValuePair(param.getKey(), ObjectUtils.asString(param.getValue()))); - } - } - - - return requestParams; - } -} diff --git a/cloudinary-http43/src/main/java/com/cloudinary/http43/UploaderStrategy.java b/cloudinary-http43/src/main/java/com/cloudinary/http43/UploaderStrategy.java deleted file mode 100644 index 88ce4b90..00000000 --- a/cloudinary-http43/src/main/java/com/cloudinary/http43/UploaderStrategy.java +++ /dev/null @@ -1,144 +0,0 @@ -package com.cloudinary.http43; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.StandardCharsets; -import java.util.Collection; -import java.util.Map; - -import com.cloudinary.ProgressCallback; -import org.apache.http.HttpHost; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.conn.HttpClientConnectionManager; -import org.apache.http.entity.ContentType; -import org.apache.http.entity.mime.HttpMultipartMode; -import org.apache.http.entity.mime.MIME; -import org.apache.http.entity.mime.MultipartEntityBuilder; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClientBuilder; -import org.apache.http.impl.client.HttpClients; -import org.cloudinary.json.JSONException; -import org.cloudinary.json.JSONObject; - -import com.cloudinary.Cloudinary; -import com.cloudinary.Uploader; -import com.cloudinary.Util; -import com.cloudinary.strategies.AbstractUploaderStrategy; -import com.cloudinary.utils.ObjectUtils; -import com.cloudinary.utils.StringUtils; - -public class UploaderStrategy extends AbstractUploaderStrategy { - - private CloseableHttpClient client = null; - - @Override - public void init(Uploader uploader) { - super.init(uploader); - - HttpClientBuilder clientBuilder = HttpClients.custom(); - clientBuilder.useSystemProperties().setUserAgent(this.cloudinary().getUserAgent() + " ApacheHTTPComponents/4.3"); - - // If the configuration specifies a proxy then apply it to the client - if (cloudinary().config.proxyHost != null && cloudinary().config.proxyPort != 0) { - HttpHost proxy = new HttpHost(cloudinary().config.proxyHost, cloudinary().config.proxyPort); - clientBuilder.setProxy(proxy); - } - - HttpClientConnectionManager connectionManager = (HttpClientConnectionManager) cloudinary().config.properties.get("connectionManager"); - if (connectionManager != null) { - clientBuilder.setConnectionManager(connectionManager); - } - - this.client = clientBuilder.build(); - } - - @SuppressWarnings({"rawtypes", "unchecked"}) - @Override - public Map callApi(String action, Map params, Map options, Object file, ProgressCallback progressCallback) throws IOException { - if (progressCallback != null){ - throw new IllegalArgumentException("Progress callback is not supported"); - } - - // initialize options if passed as null - if (options == null) { - options = ObjectUtils.emptyMap(); - } - - boolean returnError = ObjectUtils.asBoolean(options.get("return_error"), false); - - if (requiresSigning(action, options)) { - uploader.signRequestParams(params, options); - } else { - Util.clearEmpty(params); - } - - String apiUrl = buildUploadUrl(action, options); - - HttpPost postMethod = new HttpPost(apiUrl); - ApiUtils.setTimeouts(postMethod, options); - - Map extraHeaders = (Map) options.get("extra_headers"); - if (extraHeaders != null) { - for (Map.Entry header : extraHeaders.entrySet()) { - postMethod.setHeader(header.getKey(), header.getValue()); - } - } - - MultipartEntityBuilder multipart = MultipartEntityBuilder.create(); - multipart.setMode(HttpMultipartMode.BROWSER_COMPATIBLE); - multipart.setCharset(StandardCharsets.UTF_8); - ContentType contentType = ContentType.MULTIPART_FORM_DATA.withCharset(MIME.UTF8_CHARSET); - // Remove blank parameters - for (Map.Entry param : params.entrySet()) { - if (param.getValue() instanceof Collection) { - for (Object value : (Collection) param.getValue()) { - multipart.addTextBody(param.getKey() + "[]", ObjectUtils.asString(value), contentType); - } - } else { - String value = param.getValue().toString(); - if (StringUtils.isNotBlank(value)) { - multipart.addTextBody(param.getKey(), value, contentType); - } - } - } - - if(file instanceof String && !(StringUtils.isRemoteUrl((String)file))){ - File _file = new File((String) file); - if (!_file.isFile() && !_file.canRead()) { - throw new IOException("File not found or unreadable: " + file); - } - file = _file; - } - String filename = (String) options.get("filename"); - if (file instanceof File) { - if (filename == null) filename = ((File) file).getName(); - multipart.addBinaryBody("file", (File) file, ContentType.APPLICATION_OCTET_STREAM, filename); - } else if (file instanceof String) { - multipart.addTextBody("file", (String) file, contentType); - } else if (file instanceof byte[]) { - if (filename == null) filename = "file"; - multipart.addBinaryBody("file", (byte[]) file, ContentType.APPLICATION_OCTET_STREAM, filename); - } else if (file == null) { - // no-problem - } else { - throw new IOException("Unrecognized file parameter " + file); - } - postMethod.setEntity(multipart.build()); - - String responseData = null; - int code = 0; - CloseableHttpResponse response = client.execute(postMethod); - try { - code = response.getStatusLine().getStatusCode(); - InputStream responseStream = response.getEntity().getContent(); - responseData = StringUtils.read(responseStream); - } finally { - response.close(); - } - - return processResponse(returnError, code, responseData); - } - -} diff --git a/cloudinary-http43/src/main/java/com/cloudinary/http43/api/Response.java b/cloudinary-http43/src/main/java/com/cloudinary/http43/api/Response.java deleted file mode 100644 index 51cd9219..00000000 --- a/cloudinary-http43/src/main/java/com/cloudinary/http43/api/Response.java +++ /dev/null @@ -1,69 +0,0 @@ -package com.cloudinary.http43.api; - -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.apache.http.Header; -import org.apache.http.HttpResponse; - -import com.cloudinary.api.ApiResponse; -import com.cloudinary.api.RateLimit; -import com.cloudinary.utils.StringUtils; - -@SuppressWarnings("rawtypes") -public class Response extends HashMap implements ApiResponse { - private static final long serialVersionUID = -5458609797599845837L; - private HttpResponse response = null; - - @SuppressWarnings("unchecked") - public Response(HttpResponse response, Map result) { - super(result); - this.response = response; - } - - public HttpResponse getRawHttpResponse() { - return this.response; - } - - private static final Pattern RATE_LIMIT_REGEX = Pattern - .compile("X-FEATURE(\\w*)RATELIMIT(-LIMIT|-RESET|-REMAINING)", Pattern.CASE_INSENSITIVE); - private static final String RFC1123_PATTERN = "EEE, dd MMM yyyyy HH:mm:ss z"; - private static final DateFormat RFC1123 = new SimpleDateFormat(RFC1123_PATTERN, Locale.ENGLISH); - - public Map rateLimits() throws java.text.ParseException { - Header[] headers = this.response.getAllHeaders(); - Map limits = new HashMap(); - for (Header header : headers) { - Matcher m = RATE_LIMIT_REGEX.matcher(header.getName()); - if (m.matches()) { - String limitName = "Api"; - RateLimit limit = null; - if (!StringUtils.isEmpty(m.group(1))) { - limitName = m.group(1); - } - limit = limits.get(limitName); - if (limit == null) { - limit = new RateLimit(); - } - if (m.group(2).equalsIgnoreCase("-limit")) { - limit.setLimit(Long.parseLong(header.getValue())); - } else if (m.group(2).equalsIgnoreCase("-remaining")) { - limit.setRemaining(Long.parseLong(header.getValue())); - } else if (m.group(2).equalsIgnoreCase("-reset")) { - limit.setReset(RFC1123.parse(header.getValue())); - } - limits.put(limitName, limit); - } - } - return limits; - } - - public RateLimit apiRateLimit() throws java.text.ParseException { - return rateLimits().get("Api"); - } -} diff --git a/cloudinary-http43/src/test/java/com/cloudinary/test/AccountApiTest.java b/cloudinary-http43/src/test/java/com/cloudinary/test/AccountApiTest.java deleted file mode 100644 index 573a12e5..00000000 --- a/cloudinary-http43/src/test/java/com/cloudinary/test/AccountApiTest.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.cloudinary.test; - -public class AccountApiTest extends AbstractAccountApiTest { -} diff --git a/cloudinary-http43/src/test/java/com/cloudinary/test/ApiTest.java b/cloudinary-http43/src/test/java/com/cloudinary/test/ApiTest.java deleted file mode 100644 index 530b644f..00000000 --- a/cloudinary-http43/src/test/java/com/cloudinary/test/ApiTest.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.cloudinary.test; - -import com.cloudinary.api.ApiResponse; -import com.cloudinary.utils.ObjectUtils; -import org.apache.http.conn.ConnectTimeoutException; -import org.junit.Test; -import org.junit.experimental.categories.Category; - -import java.net.SocketTimeoutException; -import java.util.Map; - -public class ApiTest extends AbstractApiTest { - @Category(TimeoutTest.class) - @Test(expected = ConnectTimeoutException.class) - public void testConnectTimeoutParameter() throws Exception { - // should allow listing resources - Map options = ObjectUtils.asMap( - "max_results", 500, - "connect_timeout", 1); - ApiResponse result = cloudinary.api().resources(options); - } - - @Category(TimeoutTest.class) - @Test(expected = SocketTimeoutException.class) - public void testTimeoutParameter() throws Exception { - // should allow listing resources - Map options = ObjectUtils.asMap( - "max_results", 500, - "timeout", 1); - ApiResponse result = cloudinary.api().resources(options); - } - -} diff --git a/cloudinary-http43/src/test/java/com/cloudinary/test/FoldersApiTest.java b/cloudinary-http43/src/test/java/com/cloudinary/test/FoldersApiTest.java deleted file mode 100644 index 971bcf39..00000000 --- a/cloudinary-http43/src/test/java/com/cloudinary/test/FoldersApiTest.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.cloudinary.test; - -public class FoldersApiTest extends AbstractFoldersApiTest { -} diff --git a/cloudinary-http43/src/test/java/com/cloudinary/test/SearchTest.java b/cloudinary-http43/src/test/java/com/cloudinary/test/SearchTest.java deleted file mode 100644 index 16a4708c..00000000 --- a/cloudinary-http43/src/test/java/com/cloudinary/test/SearchTest.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.cloudinary.test; - -public class SearchTest extends AbstractSearchTest { -} diff --git a/cloudinary-http43/src/test/java/com/cloudinary/test/StreamingProfilesApiTest.java b/cloudinary-http43/src/test/java/com/cloudinary/test/StreamingProfilesApiTest.java deleted file mode 100644 index 4e763579..00000000 --- a/cloudinary-http43/src/test/java/com/cloudinary/test/StreamingProfilesApiTest.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.cloudinary.test; - -/** - * Created by amir on 25/10/2016. - */ -public class StreamingProfilesApiTest extends AbstractStreamingProfilesApiTest { -} diff --git a/cloudinary-http43/src/test/java/com/cloudinary/test/StructuredMetadataTest.java b/cloudinary-http43/src/test/java/com/cloudinary/test/StructuredMetadataTest.java deleted file mode 100644 index 900da239..00000000 --- a/cloudinary-http43/src/test/java/com/cloudinary/test/StructuredMetadataTest.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.cloudinary.test; - -public class StructuredMetadataTest extends AbstractStructuredMetadataTest { -} \ No newline at end of file diff --git a/cloudinary-http43/src/test/java/com/cloudinary/test/UploaderTest.java b/cloudinary-http43/src/test/java/com/cloudinary/test/UploaderTest.java deleted file mode 100644 index efbf9190..00000000 --- a/cloudinary-http43/src/test/java/com/cloudinary/test/UploaderTest.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.cloudinary.test; - -import com.cloudinary.api.ApiResponse; -import com.cloudinary.utils.ObjectUtils; -import org.apache.http.conn.ConnectTimeoutException; -import org.junit.Test; -import org.junit.experimental.categories.Category; - -import java.net.SocketTimeoutException; -import java.util.Map; - -public class UploaderTest extends AbstractUploaderTest { - - @Category(TimeoutTest.class) - @Test(expected = ConnectTimeoutException.class) - public void testConnectTimeoutParameter() throws Exception { - // should allow listing resources - Map options = ObjectUtils.asMap( - "max_results", 500, - "connect_timeout", 1); - ApiResponse result = cloudinary.api().resources(options); - } - - @Category(TimeoutTest.class) - @Test(expected = SocketTimeoutException.class) - public void testTimeoutParameter() throws Exception { - // should allow listing resources - Map options = ObjectUtils.asMap( - "max_results", 500, - "timeout", 1); - ApiResponse result = cloudinary.api().resources(options); - } - -} \ No newline at end of file diff --git a/cloudinary-http44/build.gradle b/cloudinary-http44/build.gradle deleted file mode 100644 index a4c51ed8..00000000 --- a/cloudinary-http44/build.gradle +++ /dev/null @@ -1,113 +0,0 @@ -plugins { - id 'java-library' - id 'signing' - id 'maven-publish' - id 'io.codearte.nexus-staging' version '0.21.1' -} - -apply from: "../java_shared.gradle" - -task ciTest( type: Test ) { - useJUnit { - excludeCategories 'com.cloudinary.test.TimeoutTest' - if (System.getProperty("CLOUDINARY_ACCOUNT_URL") == "") { - exclude '**/AccountApiTest.class' - } - } -} - -dependencies { - compile project(':cloudinary-core') - compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.1' - compile group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.4' - compile group: 'org.apache.httpcomponents', name: 'httpmime', version: '4.4' - testCompile project(':cloudinary-test-common') - testCompile group: 'org.hamcrest', name: 'java-hamcrest', version: '2.0.0.0' - testCompile group: 'pl.pragmatists', name: 'JUnitParams', version: '1.0.5' - testCompile group: 'junit', name: 'junit', version: '4.12' -} - -if (hasProperty("ossrhPassword")) { - - signing { - sign configurations.archives - } - - nexusStaging { - packageGroup = group - username = project.hasProperty("ossrhUsername") ? project.ext["ossrhUsername"] : "" - password = project.hasProperty("ossrhPassword") ? project.ext["ossrhPassword"] : "" - } - - publishing { - publications { - mavenJava(MavenPublication) { - from components.java - artifact sourcesJar - artifact javadocJar - pom { - name = 'Cloudinary Apache HTTP 4.4 Library' - packaging = 'jar' - groupId = publishGroupId - artifactId = 'cloudinary-http44' - description = publishDescription - url = githubUrl - licenses { - license { - name = licenseName - url = licenseUrl - } - } - - developers { - developer { - id = developerId - name = developerName - email = developerEmail - } - } - scm { - connection = scmConnection - developerConnection = scmDeveloperConnection - url = scmUrl - } - } - - pom.withXml { - def pomFile = file("${project.buildDir}/generated-pom.xml") - writeTo(pomFile) - def pomAscFile = signing.sign(pomFile).signatureFiles[0] - artifact(pomAscFile) { - classifier = null - extension = 'pom.asc' - } - } - - // create the signed artifacts - project.tasks.signArchives.signatureFiles.each { - artifact(it) { - def matcher = it.file =~ /-(sources|javadoc)\.jar\.asc$/ - if (matcher.find()) { - classifier = matcher.group(1) - } else { - classifier = null - } - extension = 'jar.asc' - } - } - } - } - - model { - tasks.generatePomFileForMavenJavaPublication { - destination = file("$buildDir/generated-pom.xml") - } - tasks.publishMavenJavaPublicationToMavenLocal { - dependsOn project.tasks.signArchives - } - tasks.publishMavenJavaPublicationToSonatypeRepository { - dependsOn project.tasks.signArchives - } - } - } -} diff --git a/cloudinary-http44/src/main/java/com/cloudinary/http44/ApiStrategy.java b/cloudinary-http44/src/main/java/com/cloudinary/http44/ApiStrategy.java deleted file mode 100644 index b74f1dd7..00000000 --- a/cloudinary-http44/src/main/java/com/cloudinary/http44/ApiStrategy.java +++ /dev/null @@ -1,204 +0,0 @@ -package com.cloudinary.http44; - -import com.cloudinary.Api; -import com.cloudinary.Api.HttpMethod; -import com.cloudinary.Cloudinary; -import com.cloudinary.api.ApiResponse; -import com.cloudinary.api.exceptions.GeneralError; -import com.cloudinary.http44.api.Response; -import com.cloudinary.utils.Base64Coder; -import com.cloudinary.utils.ObjectUtils; -import com.cloudinary.utils.StringUtils; -import org.apache.http.Consts; -import org.apache.http.HttpEntity; -import org.apache.http.HttpHost; -import org.apache.http.NameValuePair; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.entity.UrlEncodedFormEntity; -import org.apache.http.client.methods.*; -import org.apache.http.client.utils.URIBuilder; -import org.apache.http.conn.HttpClientConnectionManager; -import org.apache.http.entity.ContentType; -import org.apache.http.entity.StringEntity; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClientBuilder; -import org.apache.http.impl.client.HttpClients; -import org.apache.http.util.EntityUtils; -import org.cloudinary.json.JSONException; -import org.cloudinary.json.JSONObject; - -import java.io.InputStream; -import java.io.UnsupportedEncodingException; -import java.lang.reflect.Constructor; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static com.cloudinary.http44.ApiUtils.prepareParams; -import static com.cloudinary.http44.ApiUtils.setTimeouts; - -public class ApiStrategy extends com.cloudinary.strategies.AbstractApiStrategy { - - private CloseableHttpClient client = null; - - @Override - public void init(Api api) { - super.init(api); - - HttpClientBuilder clientBuilder = HttpClients.custom(); - clientBuilder.useSystemProperties().setUserAgent(this.api.cloudinary.getUserAgent() + " ApacheHTTPComponents/4.4"); - - // If the configuration specifies a proxy then apply it to the client - if (api.cloudinary.config.proxyHost != null && api.cloudinary.config.proxyPort != 0) { - HttpHost proxy = new HttpHost(api.cloudinary.config.proxyHost, api.cloudinary.config.proxyPort); - clientBuilder.setProxy(proxy); - } - - HttpClientConnectionManager connectionManager = (HttpClientConnectionManager) api.cloudinary.config.properties.get("connectionManager"); - if (connectionManager != null) { - clientBuilder.setConnectionManager(connectionManager); - } - - int timeout = this.api.cloudinary.config.timeout; - if (timeout > 0) { - RequestConfig config = RequestConfig.custom() - .setSocketTimeout(timeout * 1000) - .setConnectTimeout(timeout * 1000) - .build(); - clientBuilder.setDefaultRequestConfig(config); - } - - this.client = clientBuilder.build(); - } - - @SuppressWarnings({"rawtypes", "unchecked"}) - public ApiResponse callApi(HttpMethod method, Iterable uri, Map params, Map options) throws Exception { - if (options == null) - options = ObjectUtils.emptyMap(); - - String apiKey = ObjectUtils.asString(options.get("api_key"), this.api.cloudinary.config.apiKey); - String apiSecret = ObjectUtils.asString(options.get("api_secret"), this.api.cloudinary.config.apiSecret); - String oauthToken = ObjectUtils.asString(options.get("oauth_token"), this.api.cloudinary.config.oauthToken); - - validateAuthorization(apiKey, apiSecret, oauthToken); - - String apiUrl = createApiUrl(uri, options); - HttpUriRequest request = prepareRequest(method, apiUrl, params, options); - - request.setHeader("Authorization", getAuthorizationHeaderValue(apiKey, apiSecret, oauthToken)); - - return getApiResponse(request); - } - - private ApiResponse getApiResponse(HttpUriRequest request) throws Exception { - String responseData = null; - int code = 0; - CloseableHttpResponse response = client.execute(request); - try { - code = response.getStatusLine().getStatusCode(); - final HttpEntity entity = response.getEntity(); - responseData = StringUtils.read(entity.getContent()); - EntityUtils.consume(entity); - } finally { - response.close(); - } - - Class exceptionClass = Api.CLOUDINARY_API_ERROR_CLASSES.get(code); - if (code != 200 && exceptionClass == null) { - throw new GeneralError("Server returned unexpected status code - " + code + " - " + responseData); - } - Map result; - - try { - JSONObject responseJSON = new JSONObject(responseData); - result = ObjectUtils.toMap(responseJSON); - } catch (JSONException e) { - throw new RuntimeException("Invalid JSON response from server " + e.getMessage()); - } - - if (code == 200) { - return new Response(response, result); - } else { - String message = (String) ((Map) result.get("error")).get("message"); - Constructor exceptionConstructor = exceptionClass.getConstructor(String.class); - throw exceptionConstructor.newInstance(message); - } - } - - @Override - public ApiResponse callAccountApi(HttpMethod method, Iterable uri, Map params, Map options) throws Exception { - if (options == null) - options = ObjectUtils.emptyMap(); - - String prefix = ObjectUtils.asString(options.get("upload_prefix"), "https://api.cloudinary.com"); - String apiKey = ObjectUtils.asString(options.get("provisioning_api_key")); - if (apiKey == null) throw new IllegalArgumentException("Must supply provisioning_api_key"); - String apiSecret = ObjectUtils.asString(options.get("provisioning_api_secret")); - if (apiSecret == null) throw new IllegalArgumentException("Must supply provisioning_api_secret"); - - String apiUrl = StringUtils.join(Arrays.asList(prefix, "v1_1"), "/"); - for (String component : uri) { - apiUrl = apiUrl + "/" + component; - } - - HttpUriRequest request = prepareRequest(method, apiUrl, params, options); - - request.setHeader("Authorization", getAuthorizationHeaderValue(apiKey, apiSecret, null)); - - return getApiResponse(request); - } - - /** - * Prepare a request with the URL and parameters based on the HTTP method used - * - * @param method the HTTP method: GET, PUT, POST, DELETE - * @param apiUrl the cloudinary API URI - * @param params the parameters to pass to the server - * @return an HTTP request - * @throws URISyntaxException - * @throws UnsupportedEncodingException - */ - private HttpUriRequest prepareRequest(HttpMethod method, String apiUrl, Map params, Map options) throws URISyntaxException, UnsupportedEncodingException { - URI apiUri; - HttpRequestBase request; - - String contentType = ObjectUtils.asString(options.get("content_type"), "urlencoded"); - URIBuilder apiUrlBuilder = new URIBuilder(apiUrl); - List urlEncodedParams = prepareParams(params); - - if (method == HttpMethod.GET) { - apiUrlBuilder.setParameters(prepareParams(params)); - apiUri = apiUrlBuilder.build(); - request = new HttpGet(apiUri); - } else { - Map paramsCopy = new HashMap((Map) params); - apiUri = apiUrlBuilder.build(); - switch (method) { - case PUT: - request = new HttpPut(apiUri); - break; - case DELETE: //uses HttpPost instead of HttpDelete - paramsCopy.put("_method", "delete"); - //continue with POST - case POST: - request = new HttpPost(apiUri); - break; - default: - throw new IllegalArgumentException("Unknown HTTP method"); - } - if (contentType.equals("json")) { - JSONObject asJSON = ObjectUtils.toJSON(paramsCopy); - StringEntity requestEntity = new StringEntity(asJSON.toString(), ContentType.APPLICATION_JSON); - ((HttpEntityEnclosingRequestBase) request).setEntity(requestEntity); - } else { - ((HttpEntityEnclosingRequestBase) request).setEntity(new UrlEncodedFormEntity(prepareParams(paramsCopy), Consts.UTF_8)); - } - } - - setTimeouts(request, options); - return request; - } -} diff --git a/cloudinary-http44/src/main/java/com/cloudinary/http44/ApiUtils.java b/cloudinary-http44/src/main/java/com/cloudinary/http44/ApiUtils.java deleted file mode 100644 index 1a3da83f..00000000 --- a/cloudinary-http44/src/main/java/com/cloudinary/http44/ApiUtils.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.cloudinary.http44; - -import com.cloudinary.utils.ObjectUtils; -import org.apache.http.NameValuePair; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.methods.HttpRequestBase; -import org.apache.http.message.BasicNameValuePair; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -public class ApiUtils { - - public static void setTimeouts(HttpRequestBase request, Map options) { - RequestConfig config= request.getConfig(); - final RequestConfig.Builder builder; - if (config != null) { - builder = RequestConfig.copy(config); - } else { - builder = RequestConfig.custom(); - } - Integer timeout = (Integer) options.get("timeout"); - if(timeout != null) { - builder.setSocketTimeout(timeout); - } - Integer connectionRequestTimeout = (Integer) options.get("connection_request_timeout"); - if(connectionRequestTimeout != null) { - builder.setConnectionRequestTimeout(connectionRequestTimeout); - } - Integer connectTimeout = (Integer) options.get("connect_timeout"); - if(connectTimeout != null) { - builder.setConnectTimeout(connectTimeout); - } - request.setConfig(builder.build()); - } - - static List prepareParams(Map params) { - List requestParams = new ArrayList(params.size()); - for (Map.Entry param : params.entrySet()) { - if (param.getValue() instanceof Iterable) { - for (Object single : (Iterable) param.getValue()) { - requestParams.add(new BasicNameValuePair(param.getKey() + "[]", ObjectUtils.asString(single))); - } - } else { - requestParams.add(new BasicNameValuePair(param.getKey(), ObjectUtils.asString(param.getValue()))); - } - } - - - return requestParams; - } -} diff --git a/cloudinary-http44/src/main/java/com/cloudinary/http44/UploaderStrategy.java b/cloudinary-http44/src/main/java/com/cloudinary/http44/UploaderStrategy.java deleted file mode 100644 index 3afc8bce..00000000 --- a/cloudinary-http44/src/main/java/com/cloudinary/http44/UploaderStrategy.java +++ /dev/null @@ -1,145 +0,0 @@ -package com.cloudinary.http44; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.lang.reflect.Field; -import java.nio.charset.StandardCharsets; -import java.util.Collection; -import java.util.Map; - -import com.cloudinary.ProgressCallback; -import org.apache.http.HttpHost; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.conn.HttpClientConnectionManager; -import org.apache.http.entity.ContentType; -import org.apache.http.entity.mime.HttpMultipartMode; -import org.apache.http.entity.mime.MIME; -import org.apache.http.entity.mime.MultipartEntityBuilder; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClientBuilder; -import org.apache.http.impl.client.HttpClients; -import org.cloudinary.json.JSONException; -import org.cloudinary.json.JSONObject; - -import com.cloudinary.Cloudinary; -import com.cloudinary.Uploader; -import com.cloudinary.Util; -import com.cloudinary.strategies.AbstractUploaderStrategy; -import com.cloudinary.utils.ObjectUtils; -import com.cloudinary.utils.StringUtils; - -public class UploaderStrategy extends AbstractUploaderStrategy { - - private CloseableHttpClient client = null; - - @Override - public void init(Uploader uploader) { - super.init(uploader); - - HttpClientBuilder clientBuilder = HttpClients.custom(); - clientBuilder.useSystemProperties().setUserAgent(this.cloudinary().getUserAgent() + " ApacheHTTPComponents/4.4"); - - // If the configuration specifies a proxy then apply it to the client - if (cloudinary().config.proxyHost != null && cloudinary().config.proxyPort != 0) { - HttpHost proxy = new HttpHost(cloudinary().config.proxyHost, cloudinary().config.proxyPort); - clientBuilder.setProxy(proxy); - } - - HttpClientConnectionManager connectionManager = (HttpClientConnectionManager) cloudinary().config.properties.get("connectionManager"); - if (connectionManager != null) { - clientBuilder.setConnectionManager(connectionManager); - } - - this.client = clientBuilder.build(); - } - - @SuppressWarnings({"rawtypes", "unchecked"}) - @Override - public Map callApi(String action, Map params, Map options, Object file, ProgressCallback progressCallback) throws IOException { - if (progressCallback != null){ - throw new IllegalArgumentException("Progress callback is not supported"); - } - - // initialize options if passed as null - if (options == null) { - options = ObjectUtils.emptyMap(); - } - - boolean returnError = ObjectUtils.asBoolean(options.get("return_error"), false); - - if (requiresSigning(action, options)) { - uploader.signRequestParams(params, options); - } else { - Util.clearEmpty(params); - } - - String apiUrl = buildUploadUrl(action, options); - - HttpPost postMethod = new HttpPost(apiUrl); - ApiUtils.setTimeouts(postMethod, options); - - Map extraHeaders = (Map) options.get("extra_headers"); - if (extraHeaders != null) { - for (Map.Entry header : extraHeaders.entrySet()) { - postMethod.setHeader(header.getKey(), header.getValue()); - } - } - - MultipartEntityBuilder multipart = MultipartEntityBuilder.create(); - multipart.setMode(HttpMultipartMode.BROWSER_COMPATIBLE); - multipart.setCharset(StandardCharsets.UTF_8); - ContentType contentType = ContentType.MULTIPART_FORM_DATA.withCharset(MIME.UTF8_CHARSET); - // Remove blank parameters - for (Map.Entry param : params.entrySet()) { - if (param.getValue() instanceof Collection) { - for (Object value : (Collection) param.getValue()) { - multipart.addTextBody(param.getKey() + "[]", ObjectUtils.asString(value), contentType); - } - } else { - String value = param.getValue().toString(); - if (StringUtils.isNotBlank(value)) { - multipart.addTextBody(param.getKey(), value, contentType); - } - } - } - - if (file instanceof String && !StringUtils.isRemoteUrl((String) file)) { - File _file = new File((String) file); - if (!_file.isFile() && !_file.canRead()) { - throw new IOException("File not found or unreadable: " + file); - } - file = _file; - } - String filename = (String) options.get("filename"); - if (file instanceof File) { - if (filename == null) filename = ((File) file).getName(); - multipart.addBinaryBody("file", (File) file, ContentType.APPLICATION_OCTET_STREAM, filename); - } else if (file instanceof String) { - multipart.addTextBody("file", (String) file, contentType); - } else if (file instanceof byte[]) { - if (filename == null) filename = "file"; - multipart.addBinaryBody("file", (byte[]) file, ContentType.APPLICATION_OCTET_STREAM, filename); - } else if (file == null) { - // no-problem - } else { - throw new IOException("Unrecognized file parameter " + file); - } - postMethod.setEntity(multipart.build()); - - String responseData = null; - int code = 0; - CloseableHttpResponse response = client.execute(postMethod); - try { - code = response.getStatusLine().getStatusCode(); - InputStream responseStream = response.getEntity().getContent(); - responseData = StringUtils.read(responseStream); - } finally { - response.close(); - } - - Map result = processResponse(returnError, code, responseData); - return result; - } -} diff --git a/cloudinary-http44/src/main/java/com/cloudinary/http44/api/Response.java b/cloudinary-http44/src/main/java/com/cloudinary/http44/api/Response.java deleted file mode 100644 index 0036d453..00000000 --- a/cloudinary-http44/src/main/java/com/cloudinary/http44/api/Response.java +++ /dev/null @@ -1,69 +0,0 @@ -package com.cloudinary.http44.api; - -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.apache.http.Header; -import org.apache.http.HttpResponse; - -import com.cloudinary.api.ApiResponse; -import com.cloudinary.api.RateLimit; -import com.cloudinary.utils.StringUtils; - -@SuppressWarnings("rawtypes") -public class Response extends HashMap implements ApiResponse { - private static final long serialVersionUID = -5458609797599845837L; - private HttpResponse response = null; - - @SuppressWarnings("unchecked") - public Response(HttpResponse response, Map result) { - super(result); - this.response = response; - } - - public HttpResponse getRawHttpResponse() { - return this.response; - } - - private static final Pattern RATE_LIMIT_REGEX = Pattern - .compile("X-FEATURE(\\w*)RATELIMIT(-LIMIT|-RESET|-REMAINING)", Pattern.CASE_INSENSITIVE); - private static final String RFC1123_PATTERN = "EEE, dd MMM yyyyy HH:mm:ss z"; - private static final DateFormat RFC1123 = new SimpleDateFormat(RFC1123_PATTERN, Locale.ENGLISH); - - public Map rateLimits() throws java.text.ParseException { - Header[] headers = this.response.getAllHeaders(); - Map limits = new HashMap(); - for (Header header : headers) { - Matcher m = RATE_LIMIT_REGEX.matcher(header.getName()); - if (m.matches()) { - String limitName = "Api"; - RateLimit limit = null; - if (!StringUtils.isEmpty(m.group(1))) { - limitName = m.group(1); - } - limit = limits.get(limitName); - if (limit == null) { - limit = new RateLimit(); - } - if (m.group(2).equalsIgnoreCase("-limit")) { - limit.setLimit(Long.parseLong(header.getValue())); - } else if (m.group(2).equalsIgnoreCase("-remaining")) { - limit.setRemaining(Long.parseLong(header.getValue())); - } else if (m.group(2).equalsIgnoreCase("-reset")) { - limit.setReset(RFC1123.parse(header.getValue())); - } - limits.put(limitName, limit); - } - } - return limits; - } - - public RateLimit apiRateLimit() throws java.text.ParseException { - return rateLimits().get("Api"); - } -} diff --git a/cloudinary-http44/src/test/java/com/cloudinary/test/AccountApiTest.java b/cloudinary-http44/src/test/java/com/cloudinary/test/AccountApiTest.java deleted file mode 100644 index 573a12e5..00000000 --- a/cloudinary-http44/src/test/java/com/cloudinary/test/AccountApiTest.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.cloudinary.test; - -public class AccountApiTest extends AbstractAccountApiTest { -} diff --git a/cloudinary-http44/src/test/java/com/cloudinary/test/ApiTest.java b/cloudinary-http44/src/test/java/com/cloudinary/test/ApiTest.java deleted file mode 100644 index c39a89e2..00000000 --- a/cloudinary-http44/src/test/java/com/cloudinary/test/ApiTest.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.cloudinary.test; - -import com.cloudinary.api.ApiResponse; -import com.cloudinary.utils.ObjectUtils; -import org.apache.http.conn.ConnectTimeoutException; -import org.junit.Test; -import org.junit.experimental.categories.Category; - -import java.net.SocketTimeoutException; -import java.util.Map; - -public class ApiTest extends AbstractApiTest { - @Category(TimeoutTest.class) - @Test(expected = ConnectTimeoutException.class) - public void testConnectTimeoutParameter() throws Exception { - // should allow listing resources - Map options = ObjectUtils.asMap( - "max_results", 500, - "connect_timeout", 1); - ApiResponse result = cloudinary.api().resources(options); - } - - @Category(TimeoutTest.class) - @Test(expected = SocketTimeoutException.class) - public void testTimeoutParameter() throws Exception { - // should allow listing resources - Map options = ObjectUtils.asMap( - "max_results", 500, - "timeout", 1); - ApiResponse result = cloudinary.api().resources(options); - } -} diff --git a/cloudinary-http44/src/test/java/com/cloudinary/test/ContextTest.java b/cloudinary-http44/src/test/java/com/cloudinary/test/ContextTest.java deleted file mode 100644 index 4841e9f6..00000000 --- a/cloudinary-http44/src/test/java/com/cloudinary/test/ContextTest.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.cloudinary.test; - -public class ContextTest extends AbstractContextTest { - -} \ No newline at end of file diff --git a/cloudinary-http44/src/test/java/com/cloudinary/test/FoldersApiTest.java b/cloudinary-http44/src/test/java/com/cloudinary/test/FoldersApiTest.java deleted file mode 100644 index 971bcf39..00000000 --- a/cloudinary-http44/src/test/java/com/cloudinary/test/FoldersApiTest.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.cloudinary.test; - -public class FoldersApiTest extends AbstractFoldersApiTest { -} diff --git a/cloudinary-http44/src/test/java/com/cloudinary/test/SearchTest.java b/cloudinary-http44/src/test/java/com/cloudinary/test/SearchTest.java deleted file mode 100644 index 16a4708c..00000000 --- a/cloudinary-http44/src/test/java/com/cloudinary/test/SearchTest.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.cloudinary.test; - -public class SearchTest extends AbstractSearchTest { -} diff --git a/cloudinary-http44/src/test/java/com/cloudinary/test/StreamingProfilesApiTest.java b/cloudinary-http44/src/test/java/com/cloudinary/test/StreamingProfilesApiTest.java deleted file mode 100644 index 4e763579..00000000 --- a/cloudinary-http44/src/test/java/com/cloudinary/test/StreamingProfilesApiTest.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.cloudinary.test; - -/** - * Created by amir on 25/10/2016. - */ -public class StreamingProfilesApiTest extends AbstractStreamingProfilesApiTest { -} diff --git a/cloudinary-http44/src/test/java/com/cloudinary/test/StructuredMetadataTest.java b/cloudinary-http44/src/test/java/com/cloudinary/test/StructuredMetadataTest.java deleted file mode 100644 index 8cc186f4..00000000 --- a/cloudinary-http44/src/test/java/com/cloudinary/test/StructuredMetadataTest.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.cloudinary.test; - -public class StructuredMetadataTest extends AbstractStructuredMetadataTest { -} diff --git a/cloudinary-http44/src/test/java/com/cloudinary/test/UploaderTest.java b/cloudinary-http44/src/test/java/com/cloudinary/test/UploaderTest.java deleted file mode 100644 index 4734707c..00000000 --- a/cloudinary-http44/src/test/java/com/cloudinary/test/UploaderTest.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.cloudinary.test; - -import com.cloudinary.api.ApiResponse; -import com.cloudinary.utils.ObjectUtils; -import org.apache.http.conn.ConnectTimeoutException; -import org.junit.Test; -import org.junit.experimental.categories.Category; - -import java.net.SocketTimeoutException; -import java.util.Map; - -public class UploaderTest extends AbstractUploaderTest { - - @Category(TimeoutTest.class) - @Test(expected = ConnectTimeoutException.class) - public void testConnectTimeoutParameter() throws Exception { - // should allow listing resources - Map options = ObjectUtils.asMap( - "max_results", 500, - "connect_timeout", 1); - ApiResponse result = cloudinary.api().resources(options); - } - - @Category(TimeoutTest.class) - @Test(expected = SocketTimeoutException.class) - public void testTimeoutParameter() throws Exception { - // should allow listing resources - Map options = ObjectUtils.asMap( - "max_results", 500, - "timeout", 1); - ApiResponse result = cloudinary.api().resources(options); - } -} diff --git a/cloudinary-http45/build.gradle b/cloudinary-http45/build.gradle deleted file mode 100644 index f4b7613d..00000000 --- a/cloudinary-http45/build.gradle +++ /dev/null @@ -1,113 +0,0 @@ -plugins { - id 'java-library' - id 'signing' - id 'maven-publish' - id 'io.codearte.nexus-staging' version '0.21.1' -} - -apply from: "../java_shared.gradle" - -task ciTest( type: Test ) { - useJUnit { - excludeCategories 'com.cloudinary.test.TimeoutTest' - if (System.getProperty("CLOUDINARY_ACCOUNT_URL") == "") { - exclude '**/AccountApiTest.class' - } - } -} - -dependencies { - compile project(':cloudinary-core') - compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.1' - compile group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.5.13' - compile group: 'org.apache.httpcomponents', name: 'httpmime', version: '4.5.13' - testCompile project(':cloudinary-test-common') - testCompile group: 'org.hamcrest', name: 'java-hamcrest', version: '2.0.0.0' - testCompile group: 'pl.pragmatists', name: 'JUnitParams', version: '1.0.5' - testCompile group: 'junit', name: 'junit', version: '4.12' -} - -if (hasProperty("ossrhPassword")) { - - signing { - sign configurations.archives - } - - nexusStaging { - packageGroup = group - username = project.hasProperty("ossrhUsername") ? project.ext["ossrhUsername"] : "" - password = project.hasProperty("ossrhPassword") ? project.ext["ossrhPassword"] : "" - } - - publishing { - publications { - mavenJava(MavenPublication) { - from components.java - artifact sourcesJar - artifact javadocJar - pom { - name = 'Cloudinary Apache HTTP 4.5 Library' - packaging = 'jar' - groupId = publishGroupId - artifactId = 'cloudinary-http45' - description = publishDescription - url = githubUrl - licenses { - license { - name = licenseName - url = licenseUrl - } - } - - developers { - developer { - id = developerId - name = developerName - email = developerEmail - } - } - scm { - connection = scmConnection - developerConnection = scmDeveloperConnection - url = scmUrl - } - } - - pom.withXml { - def pomFile = file("${project.buildDir}/generated-pom.xml") - writeTo(pomFile) - def pomAscFile = signing.sign(pomFile).signatureFiles[0] - artifact(pomAscFile) { - classifier = null - extension = 'pom.asc' - } - } - - // create the signed artifacts - project.tasks.signArchives.signatureFiles.each { - artifact(it) { - def matcher = it.file =~ /-(sources|javadoc)\.jar\.asc$/ - if (matcher.find()) { - classifier = matcher.group(1) - } else { - classifier = null - } - extension = 'jar.asc' - } - } - } - } - - model { - tasks.generatePomFileForMavenJavaPublication { - destination = file("$buildDir/generated-pom.xml") - } - tasks.publishMavenJavaPublicationToMavenLocal { - dependsOn project.tasks.signArchives - } - tasks.publishMavenJavaPublicationToSonatypeRepository { - dependsOn project.tasks.signArchives - } - } - } -} diff --git a/cloudinary-http45/src/main/java/com/cloudinary/http45/ApiStrategy.java b/cloudinary-http45/src/main/java/com/cloudinary/http45/ApiStrategy.java deleted file mode 100644 index b4e8673a..00000000 --- a/cloudinary-http45/src/main/java/com/cloudinary/http45/ApiStrategy.java +++ /dev/null @@ -1,201 +0,0 @@ -package com.cloudinary.http45; - -import com.cloudinary.Api; -import com.cloudinary.Api.HttpMethod; -import com.cloudinary.Cloudinary; -import com.cloudinary.api.ApiResponse; -import com.cloudinary.api.exceptions.GeneralError; -import com.cloudinary.http45.api.Response; -import com.cloudinary.utils.Base64Coder; -import com.cloudinary.utils.ObjectUtils; -import com.cloudinary.utils.StringUtils; -import org.apache.http.Consts; -import org.apache.http.HttpHost; -import org.apache.http.NameValuePair; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.entity.UrlEncodedFormEntity; -import org.apache.http.client.methods.*; -import org.apache.http.client.utils.URIBuilder; -import org.apache.http.conn.HttpClientConnectionManager; -import org.apache.http.entity.ContentType; -import org.apache.http.entity.StringEntity; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClientBuilder; -import org.apache.http.impl.client.HttpClients; -import org.cloudinary.json.JSONException; -import org.cloudinary.json.JSONObject; - -import java.io.InputStream; -import java.io.UnsupportedEncodingException; -import java.lang.reflect.Constructor; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static com.cloudinary.http45.ApiUtils.prepareParams; -import static com.cloudinary.http45.ApiUtils.setTimeouts; - -public class ApiStrategy extends com.cloudinary.strategies.AbstractApiStrategy { - - private CloseableHttpClient client = null; - - @Override - public void init(Api api) { - super.init(api); - - HttpClientBuilder clientBuilder = HttpClients.custom(); - clientBuilder.useSystemProperties().setUserAgent(this.api.cloudinary.getUserAgent() + " ApacheHTTPComponents/4.5"); - - // If the configuration specifies a proxy then apply it to the client - if (api.cloudinary.config.proxyHost != null && api.cloudinary.config.proxyPort != 0) { - HttpHost proxy = new HttpHost(api.cloudinary.config.proxyHost, api.cloudinary.config.proxyPort); - clientBuilder.setProxy(proxy); - } - - HttpClientConnectionManager connectionManager = (HttpClientConnectionManager) api.cloudinary.config.properties.get("connectionManager"); - if (connectionManager != null) { - clientBuilder.setConnectionManager(connectionManager); - } - - int timeout = this.api.cloudinary.config.timeout; - if (timeout > 0) { - RequestConfig config = RequestConfig.custom() - .setSocketTimeout(timeout * 1000) - .setConnectTimeout(timeout * 1000) - .build(); - clientBuilder.setDefaultRequestConfig(config); - } - - this.client = clientBuilder.build(); - } - - @SuppressWarnings({"rawtypes", "unchecked"}) - public ApiResponse callApi(HttpMethod method, Iterable uri, Map params, Map options) throws Exception { - if (options == null) - options = ObjectUtils.emptyMap(); - - String apiKey = ObjectUtils.asString(options.get("api_key"), this.api.cloudinary.config.apiKey); - String apiSecret = ObjectUtils.asString(options.get("api_secret"), this.api.cloudinary.config.apiSecret); - String oauthToken = ObjectUtils.asString(options.get("oauth_token"), this.api.cloudinary.config.oauthToken); - - validateAuthorization(apiKey, apiSecret, oauthToken); - - String apiUrl = createApiUrl(uri, options); - HttpUriRequest request = prepareRequest(method, apiUrl, params, options); - - request.setHeader("Authorization", getAuthorizationHeaderValue(apiKey, apiSecret, oauthToken)); - - return getApiResponse(request); - } - - private ApiResponse getApiResponse(HttpUriRequest request) throws Exception { - String responseData = null; - int code = 0; - CloseableHttpResponse response = client.execute(request); - try { - code = response.getStatusLine().getStatusCode(); - InputStream responseStream = response.getEntity().getContent(); - responseData = StringUtils.read(responseStream); - } finally { - response.close(); - } - - Class exceptionClass = Api.CLOUDINARY_API_ERROR_CLASSES.get(code); - if (code != 200 && exceptionClass == null) { - throw new GeneralError("Server returned unexpected status code - " + code + " - " + responseData); - } - Map result; - - try { - JSONObject responseJSON = new JSONObject(responseData); - result = ObjectUtils.toMap(responseJSON); - } catch (JSONException e) { - throw new RuntimeException("Invalid JSON response from server " + e.getMessage()); - } - - if (code == 200) { - return new Response(response, result); - } else { - String message = (String) ((Map) result.get("error")).get("message"); - Constructor exceptionConstructor = exceptionClass.getConstructor(String.class); - throw exceptionConstructor.newInstance(message); - } - } - - @Override - public ApiResponse callAccountApi(HttpMethod method, Iterable uri, Map params, Map options) throws Exception { - if (options == null) - options = ObjectUtils.emptyMap(); - - String prefix = ObjectUtils.asString(options.get("upload_prefix"), "https://api.cloudinary.com"); - String apiKey = ObjectUtils.asString(options.get("provisioning_api_key")); - if (apiKey == null) throw new IllegalArgumentException("Must supply provisioning_api_key"); - String apiSecret = ObjectUtils.asString(options.get("provisioning_api_secret")); - if (apiSecret == null) throw new IllegalArgumentException("Must supply provisioning_api_secret"); - - String apiUrl = StringUtils.join(Arrays.asList(prefix, "v1_1"), "/"); - for (String component : uri) { - apiUrl = apiUrl + "/" + component; - } - - HttpUriRequest request = prepareRequest(method, apiUrl, params, options); - - request.setHeader("Authorization", getAuthorizationHeaderValue(apiKey, apiSecret, null)); - - return getApiResponse(request); - } - - /** - * Prepare a request with the URL and parameters based on the HTTP method used - * - * @param method the HTTP method: GET, PUT, POST, DELETE - * @param apiUrl the cloudinary API URI - * @param params the parameters to pass to the server - * @return an HTTP request - * @throws URISyntaxException - * @throws UnsupportedEncodingException - */ - private HttpUriRequest prepareRequest(HttpMethod method, String apiUrl, Map params, Map options) throws URISyntaxException, UnsupportedEncodingException { - URI apiUri; - HttpRequestBase request; - - String contentType = ObjectUtils.asString(options.get("content_type"), "urlencoded"); - URIBuilder apiUrlBuilder = new URIBuilder(apiUrl); - List urlEncodedParams = prepareParams(params); - - if (method == HttpMethod.GET) { - apiUrlBuilder.setParameters(prepareParams(params)); - apiUri = apiUrlBuilder.build(); - request = new HttpGet(apiUri); - } else { - Map paramsCopy = new HashMap((Map) params); - apiUri = apiUrlBuilder.build(); - switch (method) { - case PUT: - request = new HttpPut(apiUri); - break; - case DELETE: //uses HttpPost instead of HttpDelete - paramsCopy.put("_method", "delete"); - //continue with POST - case POST: - request = new HttpPost(apiUri); - break; - default: - throw new IllegalArgumentException("Unknown HTTP method"); - } - if (contentType.equals("json")) { - JSONObject asJSON = ObjectUtils.toJSON(paramsCopy); - StringEntity requestEntity = new StringEntity(asJSON.toString(), ContentType.APPLICATION_JSON); - ((HttpEntityEnclosingRequestBase) request).setEntity(requestEntity); - } else { - ((HttpEntityEnclosingRequestBase) request).setEntity(new UrlEncodedFormEntity(prepareParams(paramsCopy), Consts.UTF_8)); - } - } - - setTimeouts(request, options); - return request; - } -} diff --git a/cloudinary-http45/src/main/java/com/cloudinary/http45/ApiUtils.java b/cloudinary-http45/src/main/java/com/cloudinary/http45/ApiUtils.java deleted file mode 100644 index 6639b9cc..00000000 --- a/cloudinary-http45/src/main/java/com/cloudinary/http45/ApiUtils.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.cloudinary.http45; - -import com.cloudinary.utils.ObjectUtils; -import org.apache.http.NameValuePair; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.methods.HttpRequestBase; -import org.apache.http.message.BasicNameValuePair; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -public class ApiUtils { - - public static void setTimeouts(HttpRequestBase request, Map options) { - RequestConfig config= request.getConfig(); - final RequestConfig.Builder builder; - if (config != null) { - builder = RequestConfig.copy(config); - } else { - builder = RequestConfig.custom(); - } - Integer timeout = (Integer) options.get("timeout"); - if(timeout != null) { - builder.setSocketTimeout(timeout); - } - Integer connectionRequestTimeout = (Integer) options.get("connection_request_timeout"); - if(connectionRequestTimeout != null) { - builder.setConnectionRequestTimeout(connectionRequestTimeout); - } - Integer connectTimeout = (Integer) options.get("connect_timeout"); - if(connectTimeout != null) { - builder.setConnectTimeout(connectTimeout); - } - request.setConfig(builder.build()); - } - - static List prepareParams(Map params) { - List requestParams = new ArrayList(params.size()); - for (Map.Entry param : params.entrySet()) { - if (param.getValue() instanceof Iterable) { - for (Object single : (Iterable) param.getValue()) { - requestParams.add(new BasicNameValuePair(param.getKey() + "[]", ObjectUtils.asString(single))); - } - } else { - requestParams.add(new BasicNameValuePair(param.getKey(), ObjectUtils.asString(param.getValue()))); - } - } - - - return requestParams; - } -} diff --git a/cloudinary-http45/src/main/java/com/cloudinary/http45/UploaderStrategy.java b/cloudinary-http45/src/main/java/com/cloudinary/http45/UploaderStrategy.java deleted file mode 100644 index f4712515..00000000 --- a/cloudinary-http45/src/main/java/com/cloudinary/http45/UploaderStrategy.java +++ /dev/null @@ -1,141 +0,0 @@ -package com.cloudinary.http45; - -import com.cloudinary.Cloudinary; -import com.cloudinary.ProgressCallback; -import com.cloudinary.Uploader; -import com.cloudinary.Util; -import com.cloudinary.strategies.AbstractUploaderStrategy; -import com.cloudinary.utils.ObjectUtils; -import com.cloudinary.utils.StringUtils; -import org.apache.http.HttpHost; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.conn.HttpClientConnectionManager; -import org.apache.http.entity.ContentType; -import org.apache.http.entity.mime.HttpMultipartMode; -import org.apache.http.entity.mime.MIME; -import org.apache.http.entity.mime.MultipartEntityBuilder; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClientBuilder; -import org.apache.http.impl.client.HttpClients; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.StandardCharsets; -import java.util.Collection; -import java.util.Map; - -public class UploaderStrategy extends AbstractUploaderStrategy { - - private CloseableHttpClient client = null; - - @Override - public void init(Uploader uploader) { - super.init(uploader); - - HttpClientBuilder clientBuilder = HttpClients.custom(); - clientBuilder.useSystemProperties().setUserAgent(cloudinary().getUserAgent() + " ApacheHTTPComponents/4.5"); - - // If the configuration specifies a proxy then apply it to the client - if (cloudinary().config.proxyHost != null && cloudinary().config.proxyPort != 0) { - HttpHost proxy = new HttpHost(cloudinary().config.proxyHost, cloudinary().config.proxyPort); - clientBuilder.setProxy(proxy); - } - - HttpClientConnectionManager connectionManager = (HttpClientConnectionManager) cloudinary().config.properties.get("connectionManager"); - if (connectionManager != null) { - clientBuilder.setConnectionManager(connectionManager); - } - - this.client = clientBuilder.build(); - } - - @SuppressWarnings({"rawtypes", "unchecked"}) - @Override - public Map callApi(String action, Map params, Map options, Object file, ProgressCallback progressCallback) throws IOException { - if (progressCallback != null){ - throw new IllegalArgumentException("Progress callback is not supported"); - } - - // initialize options if passed as null - if (options == null) { - options = ObjectUtils.emptyMap(); - } - - boolean returnError = ObjectUtils.asBoolean(options.get("return_error"), false); - - if (requiresSigning(action, options)) { - uploader.signRequestParams(params, options); - } else { - Util.clearEmpty(params); - } - - String apiUrl = buildUploadUrl(action, options); - - HttpPost postMethod = new HttpPost(apiUrl); - ApiUtils.setTimeouts(postMethod, options); - - Map extraHeaders = (Map) options.get("extra_headers"); - if (extraHeaders != null) { - for (Map.Entry header : extraHeaders.entrySet()) { - postMethod.setHeader(header.getKey(), header.getValue()); - } - } - - MultipartEntityBuilder multipart = MultipartEntityBuilder.create(); - multipart.setMode(HttpMultipartMode.BROWSER_COMPATIBLE); - multipart.setCharset(StandardCharsets.UTF_8); - ContentType contentType = ContentType.MULTIPART_FORM_DATA.withCharset(MIME.UTF8_CHARSET); - // Remove blank parameters - for (Map.Entry param : params.entrySet()) { - if (param.getValue() instanceof Collection) { - for (Object value : (Collection) param.getValue()) { - multipart.addTextBody(param.getKey() + "[]", ObjectUtils.asString(value), contentType); - } - } else { - String value = param.getValue().toString(); - if (StringUtils.isNotBlank(value)) { - multipart.addTextBody(param.getKey(), value, contentType); - } - } - } - - if (file instanceof String && !StringUtils.isRemoteUrl((String) file)) { - File _file = new File((String) file); - if (!_file.isFile() && !_file.canRead()) { - throw new IOException("File not found or unreadable: " + file); - } - file = _file; - } - String filename = (String) options.get("filename"); - if (file instanceof File) { - if (filename == null) filename = ((File) file).getName(); - multipart.addBinaryBody("file", (File) file, ContentType.APPLICATION_OCTET_STREAM, filename); - } else if (file instanceof String) { - multipart.addTextBody("file", (String) file, contentType); - } else if (file instanceof byte[]) { - if (filename == null) filename = "file"; - multipart.addBinaryBody("file", (byte[]) file, ContentType.APPLICATION_OCTET_STREAM, filename); - } else if (file == null) { - // no-problem - } else { - throw new IOException("Unrecognized file parameter " + file); - } - postMethod.setEntity(multipart.build()); - - String responseData = null; - int code = 0; - CloseableHttpResponse response = client.execute(postMethod); - try { - code = response.getStatusLine().getStatusCode(); - InputStream responseStream = response.getEntity().getContent(); - responseData = StringUtils.read(responseStream); - } finally { - response.close(); - } - - Map result = processResponse(returnError, code, responseData); - return result; - } -} diff --git a/cloudinary-http45/src/main/java/com/cloudinary/http45/api/Response.java b/cloudinary-http45/src/main/java/com/cloudinary/http45/api/Response.java deleted file mode 100644 index 08121401..00000000 --- a/cloudinary-http45/src/main/java/com/cloudinary/http45/api/Response.java +++ /dev/null @@ -1,69 +0,0 @@ -package com.cloudinary.http45.api; - -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.apache.http.Header; -import org.apache.http.HttpResponse; - -import com.cloudinary.api.ApiResponse; -import com.cloudinary.api.RateLimit; -import com.cloudinary.utils.StringUtils; - -@SuppressWarnings("rawtypes") -public class Response extends HashMap implements ApiResponse { - private static final long serialVersionUID = -5458609797599845837L; - private HttpResponse response = null; - - @SuppressWarnings("unchecked") - public Response(HttpResponse response, Map result) { - super(result); - this.response = response; - } - - public HttpResponse getRawHttpResponse() { - return this.response; - } - - private static final Pattern RATE_LIMIT_REGEX = Pattern - .compile("X-FEATURE(\\w*)RATELIMIT(-LIMIT|-RESET|-REMAINING)", Pattern.CASE_INSENSITIVE); - private static final String RFC1123_PATTERN = "EEE, dd MMM yyyyy HH:mm:ss z"; - private static final DateFormat RFC1123 = new SimpleDateFormat(RFC1123_PATTERN, Locale.ENGLISH); - - public Map rateLimits() throws java.text.ParseException { - Header[] headers = this.response.getAllHeaders(); - Map limits = new HashMap(); - for (Header header : headers) { - Matcher m = RATE_LIMIT_REGEX.matcher(header.getName()); - if (m.matches()) { - String limitName = "Api"; - RateLimit limit = null; - if (!StringUtils.isEmpty(m.group(1))) { - limitName = m.group(1); - } - limit = limits.get(limitName); - if (limit == null) { - limit = new RateLimit(); - } - if (m.group(2).equalsIgnoreCase("-limit")) { - limit.setLimit(Long.parseLong(header.getValue())); - } else if (m.group(2).equalsIgnoreCase("-remaining")) { - limit.setRemaining(Long.parseLong(header.getValue())); - } else if (m.group(2).equalsIgnoreCase("-reset")) { - limit.setReset(RFC1123.parse(header.getValue())); - } - limits.put(limitName, limit); - } - } - return limits; - } - - public RateLimit apiRateLimit() throws java.text.ParseException { - return rateLimits().get("Api"); - } -} diff --git a/cloudinary-http45/src/test/java/com/cloudinary/test/AccountApiTest.java b/cloudinary-http45/src/test/java/com/cloudinary/test/AccountApiTest.java deleted file mode 100644 index 573a12e5..00000000 --- a/cloudinary-http45/src/test/java/com/cloudinary/test/AccountApiTest.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.cloudinary.test; - -public class AccountApiTest extends AbstractAccountApiTest { -} diff --git a/cloudinary-http45/src/test/java/com/cloudinary/test/ApiTest.java b/cloudinary-http45/src/test/java/com/cloudinary/test/ApiTest.java deleted file mode 100644 index c39a89e2..00000000 --- a/cloudinary-http45/src/test/java/com/cloudinary/test/ApiTest.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.cloudinary.test; - -import com.cloudinary.api.ApiResponse; -import com.cloudinary.utils.ObjectUtils; -import org.apache.http.conn.ConnectTimeoutException; -import org.junit.Test; -import org.junit.experimental.categories.Category; - -import java.net.SocketTimeoutException; -import java.util.Map; - -public class ApiTest extends AbstractApiTest { - @Category(TimeoutTest.class) - @Test(expected = ConnectTimeoutException.class) - public void testConnectTimeoutParameter() throws Exception { - // should allow listing resources - Map options = ObjectUtils.asMap( - "max_results", 500, - "connect_timeout", 1); - ApiResponse result = cloudinary.api().resources(options); - } - - @Category(TimeoutTest.class) - @Test(expected = SocketTimeoutException.class) - public void testTimeoutParameter() throws Exception { - // should allow listing resources - Map options = ObjectUtils.asMap( - "max_results", 500, - "timeout", 1); - ApiResponse result = cloudinary.api().resources(options); - } -} diff --git a/cloudinary-http45/src/test/java/com/cloudinary/test/ContextTest.java b/cloudinary-http45/src/test/java/com/cloudinary/test/ContextTest.java deleted file mode 100644 index 4841e9f6..00000000 --- a/cloudinary-http45/src/test/java/com/cloudinary/test/ContextTest.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.cloudinary.test; - -public class ContextTest extends AbstractContextTest { - -} \ No newline at end of file diff --git a/cloudinary-http45/src/test/java/com/cloudinary/test/FoldersApiTest.java b/cloudinary-http45/src/test/java/com/cloudinary/test/FoldersApiTest.java deleted file mode 100644 index 971bcf39..00000000 --- a/cloudinary-http45/src/test/java/com/cloudinary/test/FoldersApiTest.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.cloudinary.test; - -public class FoldersApiTest extends AbstractFoldersApiTest { -} diff --git a/cloudinary-http45/src/test/java/com/cloudinary/test/SearchTest.java b/cloudinary-http45/src/test/java/com/cloudinary/test/SearchTest.java deleted file mode 100644 index 16a4708c..00000000 --- a/cloudinary-http45/src/test/java/com/cloudinary/test/SearchTest.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.cloudinary.test; - -public class SearchTest extends AbstractSearchTest { -} diff --git a/cloudinary-http45/src/test/java/com/cloudinary/test/StreamingProfilesApiTest.java b/cloudinary-http45/src/test/java/com/cloudinary/test/StreamingProfilesApiTest.java deleted file mode 100644 index 6a2e8a31..00000000 --- a/cloudinary-http45/src/test/java/com/cloudinary/test/StreamingProfilesApiTest.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.cloudinary.test; - -public class StreamingProfilesApiTest extends AbstractStreamingProfilesApiTest { -} diff --git a/cloudinary-http45/src/test/java/com/cloudinary/test/StructuredMetadataTest.java b/cloudinary-http45/src/test/java/com/cloudinary/test/StructuredMetadataTest.java deleted file mode 100644 index 8cc186f4..00000000 --- a/cloudinary-http45/src/test/java/com/cloudinary/test/StructuredMetadataTest.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.cloudinary.test; - -public class StructuredMetadataTest extends AbstractStructuredMetadataTest { -} diff --git a/cloudinary-http45/src/test/java/com/cloudinary/test/UploaderTest.java b/cloudinary-http45/src/test/java/com/cloudinary/test/UploaderTest.java deleted file mode 100644 index efbf9190..00000000 --- a/cloudinary-http45/src/test/java/com/cloudinary/test/UploaderTest.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.cloudinary.test; - -import com.cloudinary.api.ApiResponse; -import com.cloudinary.utils.ObjectUtils; -import org.apache.http.conn.ConnectTimeoutException; -import org.junit.Test; -import org.junit.experimental.categories.Category; - -import java.net.SocketTimeoutException; -import java.util.Map; - -public class UploaderTest extends AbstractUploaderTest { - - @Category(TimeoutTest.class) - @Test(expected = ConnectTimeoutException.class) - public void testConnectTimeoutParameter() throws Exception { - // should allow listing resources - Map options = ObjectUtils.asMap( - "max_results", 500, - "connect_timeout", 1); - ApiResponse result = cloudinary.api().resources(options); - } - - @Category(TimeoutTest.class) - @Test(expected = SocketTimeoutException.class) - public void testTimeoutParameter() throws Exception { - // should allow listing resources - Map options = ObjectUtils.asMap( - "max_results", 500, - "timeout", 1); - ApiResponse result = cloudinary.api().resources(options); - } - -} \ No newline at end of file diff --git a/cloudinary-http43/build.gradle b/cloudinary-http5/build.gradle similarity index 92% rename from cloudinary-http43/build.gradle rename to cloudinary-http5/build.gradle index 47fe4701..177ecdfa 100644 --- a/cloudinary-http43/build.gradle +++ b/cloudinary-http5/build.gradle @@ -19,8 +19,8 @@ task ciTest( type: Test ) { dependencies { compile project(':cloudinary-core') compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.1' - compile group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.3.1' - compile group: 'org.apache.httpcomponents', name: 'httpmime', version: '4.3' + api group: 'org.apache.httpcomponents.client5', name: 'httpclient5', version: '5.3.1' + api group: 'org.apache.httpcomponents.core5', name: 'httpcore5', version: '5.2.5' testCompile project(':cloudinary-test-common') testCompile group: 'org.hamcrest', name: 'java-hamcrest', version: '2.0.0.0' testCompile group: 'pl.pragmatists', name: 'JUnitParams', version: '1.0.5' @@ -46,10 +46,10 @@ if (hasProperty("ossrhPassword")) { artifact sourcesJar artifact javadocJar pom { - name = 'Cloudinary Apache HTTP 4.3 Library' + name = 'Cloudinary Apache HTTP 5 Library' packaging = 'jar' groupId = publishGroupId - artifactId = 'cloudinary-http43' + artifactId = 'cloudinary-http5' description = publishDescription url = githubUrl licenses { diff --git a/cloudinary-http5/src/main/java/com/cloudinary/http5/ApiStrategy.java b/cloudinary-http5/src/main/java/com/cloudinary/http5/ApiStrategy.java new file mode 100644 index 00000000..2852225d --- /dev/null +++ b/cloudinary-http5/src/main/java/com/cloudinary/http5/ApiStrategy.java @@ -0,0 +1,163 @@ +package com.cloudinary.http5; + + +import com.cloudinary.Api; +import com.cloudinary.api.ApiResponse; +import com.cloudinary.api.exceptions.GeneralError; +import com.cloudinary.http5.api.Response; +import com.cloudinary.strategies.AbstractApiStrategy; +import com.cloudinary.utils.ObjectUtils; +import com.cloudinary.utils.StringUtils; +import org.apache.hc.client5.http.classic.methods.*; +import org.apache.hc.client5.http.entity.UrlEncodedFormEntity; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.core5.http.HttpEntity; +import org.apache.hc.core5.http.NameValuePair; +import org.apache.hc.core5.http.io.entity.EntityUtils; +import org.apache.hc.core5.http.io.entity.StringEntity; +import org.apache.hc.core5.net.URIBuilder; +import org.cloudinary.json.JSONException; +import org.cloudinary.json.JSONObject; + +import java.io.IOException; +import java.lang.reflect.Constructor; +import java.net.URISyntaxException; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import static com.cloudinary.http5.ApiUtils.prepareParams; +import static com.cloudinary.http5.ApiUtils.setTimeouts; + +public class ApiStrategy extends AbstractApiStrategy { + + private static final String APACHE_HTTP_CLIENT_VERSION = System.getProperty("apache.http.client.version", "5.3.1"); + + private CloseableHttpClient client; + + @Override + public void init(Api api) { + super.init(api); + + this.client = HttpClients.custom() + .setUserAgent(this.api.cloudinary.getUserAgent() + " ApacheHttpClient/" + APACHE_HTTP_CLIENT_VERSION) + .build(); + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + public ApiResponse callApi(Api.HttpMethod method, String apiUrl, Map params, Map options, String autorizationHeader) throws Exception { + HttpUriRequestBase request = prepareRequest(method, apiUrl, params, options); + + request.setHeader("Authorization", autorizationHeader); + + return getApiResponse(request); + } + + private ApiResponse getApiResponse(HttpUriRequestBase request) throws Exception { + String responseData = null; + int code = 0; + CloseableHttpResponse response; + try { + response = client.execute(request); + code = response.getCode(); + HttpEntity entity = response.getEntity(); + if (entity != null) { + responseData = EntityUtils.toString(entity, StandardCharsets.UTF_8); + } + } catch (IOException e) { + throw new GeneralError("Error executing request: " + e.getMessage()); + } + + if (code != 200) { + Map result; + try { + JSONObject responseJSON = new JSONObject(responseData); + result = ObjectUtils.toMap(responseJSON); + } catch (JSONException e) { + throw new RuntimeException("Invalid JSON response from server " + e.getMessage()); + } + + // Extract the error message from the result map + String message = (String) ((Map) result.get("error")).get("message"); + + // Get the appropriate exception class based on status code + Class exceptionClass = Api.CLOUDINARY_API_ERROR_CLASSES.get(code); + if (exceptionClass != null) { + Constructor exceptionConstructor = exceptionClass.getConstructor(String.class); + throw exceptionConstructor.newInstance(message); + } else { + throw new GeneralError("Server returned unexpected status code - " + code + " - " + responseData); + } + } + + Map result; + try { + JSONObject responseJSON = new JSONObject(responseData); + result = ObjectUtils.toMap(responseJSON); + } catch (JSONException e) { + throw new RuntimeException("Invalid JSON response from server " + e.getMessage()); + } + + return new Response(response, result); + } + + @Override + public ApiResponse callAccountApi(Api.HttpMethod method, String apiUrl, Map params, Map options, String authorizationHeader) throws Exception { + // Prepare the request + HttpUriRequestBase request = prepareRequest(method, apiUrl, params, options); + + // Add authorization header + + request.setHeader("Authorization", authorizationHeader); + + // Execute the request and return the response + return getApiResponse(request); + } + + private HttpUriRequestBase prepareRequest(Api.HttpMethod method, String apiUrl, Map params, Map options) throws URISyntaxException { + HttpUriRequestBase request; + + String contentType = ObjectUtils.asString(options.get("content_type"), "urlencoded"); + + switch (method) { + case GET: + URIBuilder uriBuilder = new URIBuilder(apiUrl); + for (NameValuePair param : prepareParams(params)) { + uriBuilder.addParameter(param.getName(), param.getValue()); + } + request = new HttpGet(uriBuilder.toString()); + break; + case POST: + request = new HttpPost(apiUrl); + setEntity((HttpUriRequestBase) request, params, contentType); + break; + case PUT: + request = new HttpPut(apiUrl); + setEntity((HttpUriRequestBase) request, params, contentType); + break; + case DELETE: + request = new HttpDelete(apiUrl); + setEntity((HttpUriRequestBase) request, params, contentType); + break; + default: + throw new IllegalArgumentException("Unknown HTTP method"); + } + setTimeouts(request, options); + return request; + } + + private void setEntity(HttpUriRequestBase request, Map params, String contentType) { + if ("json".equals(contentType)) { + JSONObject json = ObjectUtils.toJSON(params); + StringEntity entity = new StringEntity(json.toString(), StandardCharsets.UTF_8); + request.setEntity(entity); + request.setHeader("Content-Type", "application/json"); + } else { + List formParams = prepareParams(params); + request.setEntity(new UrlEncodedFormEntity(formParams, StandardCharsets.UTF_8)); + } + } +} diff --git a/cloudinary-http5/src/main/java/com/cloudinary/http5/ApiUtils.java b/cloudinary-http5/src/main/java/com/cloudinary/http5/ApiUtils.java new file mode 100644 index 00000000..af67a1e8 --- /dev/null +++ b/cloudinary-http5/src/main/java/com/cloudinary/http5/ApiUtils.java @@ -0,0 +1,71 @@ +package com.cloudinary.http5; + +import com.cloudinary.utils.ObjectUtils; +import org.apache.hc.client5.http.classic.methods.HttpUriRequestBase; +import org.apache.hc.client5.http.config.RequestConfig; +import org.apache.hc.core5.http.NameValuePair; +import org.apache.hc.core5.http.message.BasicNameValuePair; +import org.apache.hc.core5.util.Timeout; +import org.cloudinary.json.JSONObject; + +import java.util.*; + +public class ApiUtils { + + public static void setTimeouts(HttpUriRequestBase request, Map options) { + RequestConfig config = request.getConfig(); + final RequestConfig.Builder builder; + + if (config != null) { + builder = RequestConfig.copy(config); + } else { + builder = RequestConfig.custom(); + } + + Integer timeout = (Integer) options.get("timeout"); + if (timeout != null) { + builder.setResponseTimeout(Timeout.ofSeconds(timeout)); + } + + Integer connectionRequestTimeout = (Integer) options.get("connection_request_timeout"); + if (connectionRequestTimeout != null) { + builder.setConnectionRequestTimeout(Timeout.ofSeconds(connectionRequestTimeout)); + } + + Integer connectTimeout = (Integer) options.get("connect_timeout"); + if (connectTimeout != null) { + builder.setConnectTimeout(Timeout.ofSeconds(connectTimeout)); + } + + request.setConfig(builder.build()); + } + + + public static List prepareParams(Map params) { + List requestParams = new ArrayList<>(); + + for (Map.Entry param : params.entrySet()) { + String key = param.getKey(); + Object value = param.getValue(); + + if (value instanceof Iterable) { + // If the value is an Iterable, handle each item individually + for (Object single : (Iterable) value) { + requestParams.add(new BasicNameValuePair(key + "[]", ObjectUtils.asString(single))); + } + } else if (value instanceof Map) { + // Convert Map to JSON string manually to avoid empty object issues + JSONObject jsonObject = new JSONObject(); + for (Map.Entry entry : ((Map) value).entrySet()) { + jsonObject.put(entry.getKey().toString(), entry.getValue()); + } + requestParams.add(new BasicNameValuePair(key, jsonObject.toString())); + } else { + // Handle simple key-value pairs + requestParams.add(new BasicNameValuePair(key, ObjectUtils.asString(value))); + } + } + + return requestParams; + } +} diff --git a/cloudinary-http5/src/main/java/com/cloudinary/http5/UploaderStrategy.java b/cloudinary-http5/src/main/java/com/cloudinary/http5/UploaderStrategy.java new file mode 100644 index 00000000..5f87cbd8 --- /dev/null +++ b/cloudinary-http5/src/main/java/com/cloudinary/http5/UploaderStrategy.java @@ -0,0 +1,155 @@ +package com.cloudinary.http5; + +import com.cloudinary.ProgressCallback; +import com.cloudinary.Uploader; +import com.cloudinary.Util; +import com.cloudinary.strategies.AbstractUploaderStrategy; +import com.cloudinary.utils.ObjectUtils; +import com.cloudinary.utils.StringUtils; +import org.apache.hc.client5.http.classic.methods.HttpPost; +import org.apache.hc.client5.http.classic.methods.HttpUriRequestBase; +import org.apache.hc.client5.http.entity.mime.ByteArrayBody; +import org.apache.hc.client5.http.entity.mime.FileBody; +import org.apache.hc.client5.http.entity.mime.HttpMultipartMode; +import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.core5.http.ContentType; +import org.apache.hc.core5.http.ParseException; +import org.apache.hc.core5.http.io.entity.EntityUtils; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.Collection; +import java.util.Map; + +public class UploaderStrategy extends AbstractUploaderStrategy { + + private static final String APACHE_HTTP_CLIENT_VERSION = System.getProperty("apache.http.client.version", "5.3.1"); + + private CloseableHttpClient client; + + @Override + public void init(Uploader uploader) { + super.init(uploader); + + this.client = HttpClients.custom() + .setUserAgent(cloudinary().getUserAgent() + " ApacheHttpClient/" + APACHE_HTTP_CLIENT_VERSION) + .build(); + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + @Override + public Map callApi(String action, Map params, Map options, Object file, ProgressCallback progressCallback) throws IOException { + if (progressCallback != null) { + throw new IllegalArgumentException("Progress callback is not supported"); + } + + // Initialize options if passed as null + if (options == null) { + options = ObjectUtils.emptyMap(); + } + + boolean returnError = ObjectUtils.asBoolean(options.get("return_error"), false); + + if (requiresSigning(action, options)) { + uploader.signRequestParams(params, options); + } else { + Util.clearEmpty(params); + } + + String apiUrl = buildUploadUrl(action, options); + + // Prepare the request + HttpUriRequestBase request = prepareRequest(apiUrl, params, options, file); + + // Execute the request and handle the response + String responseData; + int code; + + try (CloseableHttpResponse response = client.execute(request)) { + code = response.getCode(); + responseData = EntityUtils.toString(response.getEntity()); + } catch (ParseException e) { + throw new RuntimeException(e); + } + + // Process and return the response + return processResponse(returnError, code, responseData); + } + + private HttpUriRequestBase prepareRequest(String apiUrl, Map params, Map options, Object file) throws IOException { + HttpPost request = new HttpPost(apiUrl); + + MultipartEntityBuilder multipartBuilder = MultipartEntityBuilder.create() + .setCharset(StandardCharsets.UTF_8).setMode(HttpMultipartMode.LEGACY); + + // Add text parameters + for (Map.Entry param : params.entrySet()) { + if (param.getValue() instanceof Collection) { + for (Object value : (Collection) param.getValue()) { + multipartBuilder.addTextBody(param.getKey() + "[]", ObjectUtils.asString(value), ContentType.TEXT_PLAIN.withCharset(StandardCharsets.UTF_8)); + } + } else { + String value = param.getValue().toString(); + if (StringUtils.isNotBlank(value)) { + multipartBuilder.addTextBody(param.getKey(), value, ContentType.TEXT_PLAIN.withCharset(StandardCharsets.UTF_8)); + } + } + } + + // Add file part + addFilePart(multipartBuilder, file, options); + + request.setEntity(multipartBuilder.build()); + + // Add extra headers if provided + Map extraHeaders = (Map) options.get("extra_headers"); + if (extraHeaders != null) { + for (Map.Entry header : extraHeaders.entrySet()) { + request.addHeader(header.getKey(), header.getValue()); + } + } + + return request; + } + + + private void addFilePart(MultipartEntityBuilder multipartBuilder, Object file, Map options) throws IOException { + String filename = (String) options.get("filename"); + + if (file instanceof String && !StringUtils.isRemoteUrl((String) file)) { + File _file = new File((String) file); + if (!_file.isFile() || !_file.canRead()) { + throw new IOException("File not found or unreadable: " + file); + } + file = _file; + } + + if (file instanceof File) { + if (filename == null) { + filename = ((File) file).getName(); + } + // Encode filename properly + filename = new String(filename.getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8); + + // Create FileBody with correct filename encoding + FileBody fileBody = new FileBody((File) file, ContentType.APPLICATION_OCTET_STREAM, filename); + multipartBuilder.addPart("file", fileBody); + } else if (file instanceof String) { + multipartBuilder.addTextBody("file", (String) file, ContentType.TEXT_PLAIN); + } else if (file instanceof byte[]) { + if (filename == null) { + filename = "file"; + } + ByteArrayBody byteArrayBody = new ByteArrayBody((byte[]) file, ContentType.APPLICATION_OCTET_STREAM, filename); + multipartBuilder.addPart("file", byteArrayBody); + } else if (file == null) { + // No file to add + } else { + throw new IOException("Unrecognized file parameter " + file); + } + } +} diff --git a/cloudinary-http42/src/main/java/com/cloudinary/http42/api/Response.java b/cloudinary-http5/src/main/java/com/cloudinary/http5/api/Response.java similarity index 72% rename from cloudinary-http42/src/main/java/com/cloudinary/http42/api/Response.java rename to cloudinary-http5/src/main/java/com/cloudinary/http5/api/Response.java index 87de8299..fd7b0980 100644 --- a/cloudinary-http42/src/main/java/com/cloudinary/http42/api/Response.java +++ b/cloudinary-http5/src/main/java/com/cloudinary/http5/api/Response.java @@ -1,7 +1,12 @@ -package com.cloudinary.http42.api; +package com.cloudinary.http5.api; -import java.text.DateFormat; +import com.cloudinary.api.ApiResponse; +import com.cloudinary.api.RateLimit; +import org.apache.hc.core5.http.Header; +import org.apache.hc.core5.http.HttpResponse; import java.text.ParseException; + +import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.HashMap; import java.util.Locale; @@ -9,20 +14,12 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.apache.http.Header; -import org.apache.http.HttpResponse; - -import com.cloudinary.api.ApiResponse; -import com.cloudinary.api.RateLimit; -import com.cloudinary.utils.StringUtils; - -@SuppressWarnings("rawtypes") public class Response extends HashMap implements ApiResponse { private static final long serialVersionUID = -5458609797599845837L; - private HttpResponse response = null; + private final HttpResponse response; @SuppressWarnings("unchecked") - public Response(HttpResponse response, Map result) { + public Response(HttpResponse response, Map result) { super(result); this.response = response; } @@ -32,25 +29,21 @@ public HttpResponse getRawHttpResponse() { } private static final Pattern RATE_LIMIT_REGEX = Pattern - .compile("X-FEATURE(\\w*)RATELIMIT(-LIMIT|-RESET|-REMAINING)", Pattern.CASE_INSENSITIVE); - private static final String RFC1123_PATTERN = "EEE, dd MMM yyyyy HH:mm:ss z"; + .compile("X-FEATURE(\\w*)RATELIMIT(-LIMIT|-RESET|-REMAINING)", Pattern.CASE_INSENSITIVE); + private static final String RFC1123_PATTERN = "EEE, dd MMM yyyy HH:mm:ss z"; private static final DateFormat RFC1123 = new SimpleDateFormat(RFC1123_PATTERN, Locale.ENGLISH); public Map rateLimits() throws ParseException { - Header[] headers = this.response.getAllHeaders(); - Map limits = new HashMap(); + Header[] headers = this.response.getHeaders(); + Map limits = new HashMap<>(); for (Header header : headers) { Matcher m = RATE_LIMIT_REGEX.matcher(header.getName()); if (m.matches()) { String limitName = "Api"; - RateLimit limit = null; - if (!StringUtils.isEmpty(m.group(1))) { + RateLimit limit = limits.getOrDefault(limitName, new RateLimit()); + if (!m.group(1).isEmpty()) { limitName = m.group(1); } - limit = limits.get(limitName); - if (limit == null) { - limit = new RateLimit(); - } if (m.group(2).equalsIgnoreCase("-limit")) { limit.setLimit(Long.parseLong(header.getValue())); } else if (m.group(2).equalsIgnoreCase("-remaining")) { diff --git a/cloudinary-http42/src/test/java/com/cloudinary/test/AccountApiTest.java b/cloudinary-http5/src/test/java/com/cloudinary/test/AccountApiTest.java similarity index 100% rename from cloudinary-http42/src/test/java/com/cloudinary/test/AccountApiTest.java rename to cloudinary-http5/src/test/java/com/cloudinary/test/AccountApiTest.java diff --git a/cloudinary-http5/src/test/java/com/cloudinary/test/ApiTest.java b/cloudinary-http5/src/test/java/com/cloudinary/test/ApiTest.java new file mode 100644 index 00000000..a2f3c89f --- /dev/null +++ b/cloudinary-http5/src/test/java/com/cloudinary/test/ApiTest.java @@ -0,0 +1,45 @@ +package com.cloudinary.test; + +import com.cloudinary.api.ApiResponse; +import com.cloudinary.utils.ObjectUtils; +import org.apache.hc.core5.util.Timeout; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import java.util.Map; + + +public class ApiTest extends AbstractApiTest { + + @Category(TimeoutTest.class) + @Test(expected = Exception.class) + public void testConnectTimeoutParameter() throws Exception { + Map options = ObjectUtils.asMap( + "max_results", 500, + "connect_timeout", 0.2); + + try { + System.out.println("Setting connect timeout to 100 ms"); + ApiResponse result = cloudinary.api().resources(options); + System.out.println("Request completed without timeout"); + } catch (Exception e) { + throw new Exception("Connection timeout", e); + } + } + + @Category(TimeoutTest.class) + @Test(expected = Exception.class) + public void testTimeoutParameter() throws Exception { + // Set a very short request timeout to trigger a timeout exception + Map options = ObjectUtils.asMap( + "max_results", 500, + "timeout", Timeout.ofMilliseconds(1000)); // Set the timeout to 1 second + + try { + ApiResponse result = cloudinary.api().resources(options); + } catch (Exception e) { + // Convert IOException to SocketTimeoutException if appropriate + throw new Exception("Socket timeout"); + } + } +} + diff --git a/cloudinary-http43/src/test/java/com/cloudinary/test/ContextTest.java b/cloudinary-http5/src/test/java/com/cloudinary/test/ContextTest.java similarity index 100% rename from cloudinary-http43/src/test/java/com/cloudinary/test/ContextTest.java rename to cloudinary-http5/src/test/java/com/cloudinary/test/ContextTest.java diff --git a/cloudinary-http42/src/test/java/com/cloudinary/test/FoldersApiTest.java b/cloudinary-http5/src/test/java/com/cloudinary/test/FoldersApiTest.java similarity index 100% rename from cloudinary-http42/src/test/java/com/cloudinary/test/FoldersApiTest.java rename to cloudinary-http5/src/test/java/com/cloudinary/test/FoldersApiTest.java diff --git a/cloudinary-http42/src/test/java/com/cloudinary/test/SearchTest.java b/cloudinary-http5/src/test/java/com/cloudinary/test/SearchTest.java similarity index 100% rename from cloudinary-http42/src/test/java/com/cloudinary/test/SearchTest.java rename to cloudinary-http5/src/test/java/com/cloudinary/test/SearchTest.java diff --git a/cloudinary-http42/src/test/java/com/cloudinary/test/StreamingProfilesApiTest.java b/cloudinary-http5/src/test/java/com/cloudinary/test/StreamingProfilesApiTest.java similarity index 100% rename from cloudinary-http42/src/test/java/com/cloudinary/test/StreamingProfilesApiTest.java rename to cloudinary-http5/src/test/java/com/cloudinary/test/StreamingProfilesApiTest.java diff --git a/cloudinary-http42/src/test/java/com/cloudinary/test/StructuredMetadataTest.java b/cloudinary-http5/src/test/java/com/cloudinary/test/StructuredMetadataTest.java similarity index 100% rename from cloudinary-http42/src/test/java/com/cloudinary/test/StructuredMetadataTest.java rename to cloudinary-http5/src/test/java/com/cloudinary/test/StructuredMetadataTest.java diff --git a/cloudinary-http42/src/test/java/com/cloudinary/test/UploaderTest.java b/cloudinary-http5/src/test/java/com/cloudinary/test/UploaderTest.java similarity index 97% rename from cloudinary-http42/src/test/java/com/cloudinary/test/UploaderTest.java rename to cloudinary-http5/src/test/java/com/cloudinary/test/UploaderTest.java index 712b0ffd..50c2a6ed 100644 --- a/cloudinary-http42/src/test/java/com/cloudinary/test/UploaderTest.java +++ b/cloudinary-http5/src/test/java/com/cloudinary/test/UploaderTest.java @@ -2,4 +2,4 @@ public class UploaderTest extends AbstractUploaderTest { -} +} \ No newline at end of file diff --git a/samples/photo_album_gae/pom.xml b/samples/photo_album_gae/pom.xml index d730e1f5..9be3ebf6 100644 --- a/samples/photo_album_gae/pom.xml +++ b/samples/photo_album_gae/pom.xml @@ -42,8 +42,8 @@ com.cloudinary - cloudinary-http42 - 1.4.1 + cloudinary-http5 + 2.0.0 org.springframework diff --git a/settings.gradle b/settings.gradle index 174cb41d..004842ea 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,8 +1,6 @@ rootProject.name = 'cloudinary-parent' include ':cloudinary-core' include ':cloudinary-taglib' +include ':cloudinary-http5' include ':cloudinary-test-common' -include ':cloudinary-http42' -include ':cloudinary-http43' -include ':cloudinary-http44' -include ':cloudinary-http45' + From 6bb07c2ca8bad7163d08df3c3d257acccde6bd0f Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Thu, 12 Sep 2024 07:54:01 +0300 Subject: [PATCH 127/150] Add `auto_chaptering` and `auto_transcription` to upload API --- .../src/main/java/com/cloudinary/Util.java | 9 ++++++++- .../cloudinary/test/AbstractUploaderTest.java | 16 ++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/cloudinary-core/src/main/java/com/cloudinary/Util.java b/cloudinary-core/src/main/java/com/cloudinary/Util.java index 99fa608c..c5fcb1f0 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Util.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Util.java @@ -11,7 +11,8 @@ public class Util { static final String[] BOOLEAN_UPLOAD_OPTIONS = new String[]{"backup", "exif", "faces", "colors", "image_metadata", "use_filename", "unique_filename", "eager_async", "invalidate", "discard_original_filename", "overwrite", "phash", "return_delete_token", "async", "quality_analysis", "cinemagraph_analysis", - "accessibility_analysis", "use_filename_as_display_name", "use_asset_folder_as_public_id_prefix", "unique_display_name", "media_metadata", "visual_search"}; + "accessibility_analysis", "use_filename_as_display_name", "use_asset_folder_as_public_id_prefix", "unique_display_name", "media_metadata", "visual_search", + "auto_chaptering", "auto_transcription"}; @SuppressWarnings({"rawtypes", "unchecked"}) public static final Map buildUploadParams(Map options) { @@ -184,6 +185,12 @@ public static final void processWriteParameters(Map options, Map if(options.get("visual_search") != null) { params.put("visual_search", options.get("visual_search")); } + if(options.get("auto_chaptering") != null) { + params.put("auto_chaptering", options.get("auto_chaptering")); + } + if(options.get("auto_transcription") != null) { + params.put("auto_transcription", options.get("auto_transcription")); + } } protected static String encodeAccessControl(Object accessControl) { diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java index 8581ca30..19098f6c 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java @@ -841,4 +841,20 @@ public void testNotificationUrl() { Map uploadParams = Util.buildUploadParams(options); Assert.assertEquals("https://www.test.com", uploadParams.get("notification_url")); } + + @Test + public void testAutoChaptering() throws Exception { + Map result = cloudinary.uploader().upload(SRC_TEST_VIDEO, asMap( + "resource_type", "video", "auto_chaptering", true)); + assert(result != null); + assertNotNull(result.get("playback_url")); + } + + @Test + public void testAutoTranscription() throws Exception { + Map result = cloudinary.uploader().upload(SRC_TEST_VIDEO, asMap( + "resource_type", "video", "auto_transcription", true)); + assert(result != null); + assertNotNull(result.get("playback_url")); + } } From 94f8977106b394bab5c2d61dc3cb0fc154df6b0f Mon Sep 17 00:00:00 2001 From: adimiz1 Date: Sun, 29 Sep 2024 15:09:20 +0300 Subject: [PATCH 128/150] Version 2.0.0 --- CHANGELOG.md | 9 +++++++++ README.md | 11 +++++++---- .../src/main/java/com/cloudinary/Cloudinary.java | 2 +- gradle.properties | 2 +- 4 files changed, 18 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f4b4cc2c..bc13fee5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +2.0.0 / 2024-09-29 +================== + +* Bump minimum Java version to 8 +* Secure true by default +* Add `auto_chaptering` and `auto_transcription` to upload API +* New Http client +* Add support for update metadata field set default disabled + 1.39.0 / 2024-07-14 =================== diff --git a/README.md b/README.md index 42a635c6..4e44ba97 100644 --- a/README.md +++ b/README.md @@ -25,9 +25,12 @@ For the complete documentation, see the [Java SDK Guide](https://cloudinary.com/ - [Upload assets to cloud](https://cloudinary.com/documentation/java_image_and_video_upload) ## Version Support -| SDK Version | Java 6+ | -|----------------|---------| -| 1.1.0 - 1.39.0 | V | +| SDK Version | Java 6+ | Java 8 | +|----------------|---------|--------| +| 1.1.0 - 1.39.0 | V | | +| 2.0.0 | | V | + + ## Installation The cloudinary_java library is available in [Maven Central](https://mvnrepository.com/artifact/com.cloudinary/cloudinary-core). To use it, add the following dependency to your pom.xml : @@ -36,7 +39,7 @@ The cloudinary_java library is available in [Maven Central](https://mvnrepositor com.cloudinary cloudinary-http45 - 1.39.0 + 2.0.0 ``` diff --git a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java index 27b347ac..9bdbe122 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java @@ -32,7 +32,7 @@ public class Cloudinary { public final static String AKAMAI_SHARED_CDN = "res.cloudinary.com"; public final static String SHARED_CDN = AKAMAI_SHARED_CDN; - public final static String VERSION = "1.39.0"; + public final static String VERSION = "2.0.0"; static String USER_AGENT_PREFIX = "CloudinaryJava"; public final static String USER_AGENT_JAVA_VERSION = "(Java " + System.getProperty("java.version") + ")"; diff --git a/gradle.properties b/gradle.properties index e588ea7d..c15a7578 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,7 +13,7 @@ developerEmail=info@cloudinary.com # These two properties must use these exact names to be compatible with 'gradle install' plugin. group=com.cloudinary -version=1.39.0 +version=2.0.0 gnsp.disableApplyOnlyOnRootProjectEnforcement=true From 43d8e9ac0c7f073017d9c4b566c9566dea95f205 Mon Sep 17 00:00:00 2001 From: adimiz1 Date: Sun, 29 Sep 2024 15:39:43 +0300 Subject: [PATCH 129/150] Fix publish script --- build.gradle | 4 ++-- cloudinary-core/build.gradle | 4 ++-- cloudinary-http5/build.gradle | 4 ++-- cloudinary-taglib/build.gradle | 4 ++-- cloudinary-test-common/build.gradle | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/build.gradle b/build.gradle index ebe374c8..5b9d6f04 100644 --- a/build.gradle +++ b/build.gradle @@ -20,8 +20,8 @@ nexusPublishing { } repositories { sonatype { - username = project.hasProperty("ossrhUsername") ? project.ext["ossrhUsername"] : "" - password = project.hasProperty("ossrhPassword") ? project.ext["ossrhPassword"] : "" + username = project.hasProperty("ossrhToken") ? project.ext["ossrhToken"] : "" + password = project.hasProperty("ossrhTokenPassword") ? project.ext["ossrhTokenPassword"] : "" } } } diff --git a/cloudinary-core/build.gradle b/cloudinary-core/build.gradle index 37246e23..01ac348b 100644 --- a/cloudinary-core/build.gradle +++ b/cloudinary-core/build.gradle @@ -23,8 +23,8 @@ if (hasProperty("ossrhPassword")) { nexusStaging { packageGroup = group - username = project.hasProperty("ossrhUsername") ? project.ext["ossrhUsername"] : "" - password = project.hasProperty("ossrhPassword") ? project.ext["ossrhPassword"] : "" + username = project.hasProperty("ossrhToken") ? project.ext["ossrhToken"] : "" + password = project.hasProperty("ossrhTokenPassword") ? project.ext["ossrhTokenPassword"] : "" } publishing { diff --git a/cloudinary-http5/build.gradle b/cloudinary-http5/build.gradle index 177ecdfa..b58b6c36 100644 --- a/cloudinary-http5/build.gradle +++ b/cloudinary-http5/build.gradle @@ -35,8 +35,8 @@ if (hasProperty("ossrhPassword")) { nexusStaging { packageGroup = group - username = project.hasProperty("ossrhUsername") ? project.ext["ossrhUsername"] : "" - password = project.hasProperty("ossrhPassword") ? project.ext["ossrhPassword"] : "" + username = project.hasProperty("ossrhToken") ? project.ext["ossrhToken"] : "" + password = project.hasProperty("ossrhTokenPassword") ? project.ext["ossrhTokenPassword"] : "" } publishing { diff --git a/cloudinary-taglib/build.gradle b/cloudinary-taglib/build.gradle index 6db5af30..16b200f3 100644 --- a/cloudinary-taglib/build.gradle +++ b/cloudinary-taglib/build.gradle @@ -30,8 +30,8 @@ if (hasProperty("ossrhPassword")) { nexusStaging { packageGroup = group - username = project.hasProperty("ossrhUsername") ? project.ext["ossrhUsername"] : "" - password = project.hasProperty("ossrhPassword") ? project.ext["ossrhPassword"] : "" + username = project.hasProperty("ossrhToken") ? project.ext["ossrhToken"] : "" + password = project.hasProperty("ossrhTokenPassword") ? project.ext["ossrhTokenPassword"] : "" } publishing { diff --git a/cloudinary-test-common/build.gradle b/cloudinary-test-common/build.gradle index 31a8bae2..daa5ce83 100644 --- a/cloudinary-test-common/build.gradle +++ b/cloudinary-test-common/build.gradle @@ -24,8 +24,8 @@ if (hasProperty("ossrhPassword")) { nexusStaging { packageGroup = group - username = project.hasProperty("ossrhUsername") ? project.ext["ossrhUsername"] : "" - password = project.hasProperty("ossrhPassword") ? project.ext["ossrhPassword"] : "" + username = project.hasProperty("ossrhToken") ? project.ext["ossrhToken"] : "" + password = project.hasProperty("ossrhTokenPassword") ? project.ext["ossrhTokenPassword"] : "" } publishing { From ab8f466972f0763c9230b683a5986e539a129cab Mon Sep 17 00:00:00 2001 From: Piotr Idzik <65706193+vil02@users.noreply.github.com> Date: Sun, 20 Oct 2024 18:57:29 +0200 Subject: [PATCH 130/150] Make utility classes proper utilities --- .../src/main/java/com/cloudinary/SmartUrlEncoder.java | 4 +++- cloudinary-core/src/main/java/com/cloudinary/Util.java | 4 +++- .../src/main/java/com/cloudinary/utils/Base64Map.java | 4 +++- .../src/main/java/com/cloudinary/utils/HtmlEscape.java | 3 ++- .../src/main/java/com/cloudinary/utils/ObjectUtils.java | 4 +++- .../src/main/java/com/cloudinary/utils/StringUtils.java | 4 +++- .../src/main/java/com/cloudinary/http5/ApiUtils.java | 3 ++- cloudinary-taglib/src/main/java/com/cloudinary/Singleton.java | 3 ++- .../src/main/java/com/cloudinary/test/AbstractApiTest.java | 2 +- .../src/main/java/com/cloudinary/test/MetadataTestHelper.java | 4 +++- .../src/main/java/com/cloudinary/test/helpers/Feature.java | 4 +++- 11 files changed, 28 insertions(+), 11 deletions(-) diff --git a/cloudinary-core/src/main/java/com/cloudinary/SmartUrlEncoder.java b/cloudinary-core/src/main/java/com/cloudinary/SmartUrlEncoder.java index bcd8f654..2f20414f 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/SmartUrlEncoder.java +++ b/cloudinary-core/src/main/java/com/cloudinary/SmartUrlEncoder.java @@ -3,7 +3,9 @@ import java.io.UnsupportedEncodingException; import java.net.URLEncoder; -public class SmartUrlEncoder { +public final class SmartUrlEncoder { + private SmartUrlEncoder() {} + public static String encode(String input) { try { return URLEncoder.encode(input, "UTF-8").replace("%2F", "/").replace("%3A", ":").replace("+", "%20"); diff --git a/cloudinary-core/src/main/java/com/cloudinary/Util.java b/cloudinary-core/src/main/java/com/cloudinary/Util.java index c5fcb1f0..f81da3cc 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Util.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Util.java @@ -8,7 +8,9 @@ import java.security.NoSuchAlgorithmException; import java.util.*; -public class Util { +public final class Util { + private Util() {} + static final String[] BOOLEAN_UPLOAD_OPTIONS = new String[]{"backup", "exif", "faces", "colors", "image_metadata", "use_filename", "unique_filename", "eager_async", "invalidate", "discard_original_filename", "overwrite", "phash", "return_delete_token", "async", "quality_analysis", "cinemagraph_analysis", "accessibility_analysis", "use_filename_as_display_name", "use_asset_folder_as_public_id_prefix", "unique_display_name", "media_metadata", "visual_search", diff --git a/cloudinary-core/src/main/java/com/cloudinary/utils/Base64Map.java b/cloudinary-core/src/main/java/com/cloudinary/utils/Base64Map.java index d5e755f9..f9948974 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/utils/Base64Map.java +++ b/cloudinary-core/src/main/java/com/cloudinary/utils/Base64Map.java @@ -3,7 +3,9 @@ import java.util.HashMap; import java.util.Map; -public class Base64Map { +public final class Base64Map { + private Base64Map() {} + public static Map values; static { diff --git a/cloudinary-core/src/main/java/com/cloudinary/utils/HtmlEscape.java b/cloudinary-core/src/main/java/com/cloudinary/utils/HtmlEscape.java index 2be36583..39ba901e 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/utils/HtmlEscape.java +++ b/cloudinary-core/src/main/java/com/cloudinary/utils/HtmlEscape.java @@ -16,7 +16,8 @@ * this program code. */ -public class HtmlEscape { +public final class HtmlEscape { + private HtmlEscape() {} private static char[] hex = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; diff --git a/cloudinary-core/src/main/java/com/cloudinary/utils/ObjectUtils.java b/cloudinary-core/src/main/java/com/cloudinary/utils/ObjectUtils.java index 437c04db..2dc607f6 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/utils/ObjectUtils.java +++ b/cloudinary-core/src/main/java/com/cloudinary/utils/ObjectUtils.java @@ -11,7 +11,9 @@ import java.util.*; -public class ObjectUtils { +public final class ObjectUtils { + private ObjectUtils() {} + /** * Formats a Date as an ISO-8601 string representation. * @param date Date to format diff --git a/cloudinary-core/src/main/java/com/cloudinary/utils/StringUtils.java b/cloudinary-core/src/main/java/com/cloudinary/utils/StringUtils.java index 0d25bacb..f8a21231 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/utils/StringUtils.java +++ b/cloudinary-core/src/main/java/com/cloudinary/utils/StringUtils.java @@ -8,7 +8,9 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -public class StringUtils { +public final class StringUtils { + private StringUtils() {} + public static final String EMPTY = ""; /** diff --git a/cloudinary-http5/src/main/java/com/cloudinary/http5/ApiUtils.java b/cloudinary-http5/src/main/java/com/cloudinary/http5/ApiUtils.java index af67a1e8..040fd714 100644 --- a/cloudinary-http5/src/main/java/com/cloudinary/http5/ApiUtils.java +++ b/cloudinary-http5/src/main/java/com/cloudinary/http5/ApiUtils.java @@ -10,7 +10,8 @@ import java.util.*; -public class ApiUtils { +public final class ApiUtils { + private ApiUtils() {} public static void setTimeouts(HttpUriRequestBase request, Map options) { RequestConfig config = request.getConfig(); diff --git a/cloudinary-taglib/src/main/java/com/cloudinary/Singleton.java b/cloudinary-taglib/src/main/java/com/cloudinary/Singleton.java index a3767492..5c11458f 100644 --- a/cloudinary-taglib/src/main/java/com/cloudinary/Singleton.java +++ b/cloudinary-taglib/src/main/java/com/cloudinary/Singleton.java @@ -10,7 +10,8 @@ * * @author jpollak */ -public class Singleton { +public final class Singleton { + private Singleton() {} private static Cloudinary cloudinary; diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java index ad89074a..e5ae3703 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java @@ -670,7 +670,7 @@ public void testRateLimits() throws Exception { @Test public void testConfiguration() throws Exception { - ApiResponse result = cloudinary.api().configuration(new ObjectUtils().asMap("settings", true)); + ApiResponse result = cloudinary.api().configuration(ObjectUtils.asMap("settings", true)); Map settings = (Map) result.get("settings"); Assert.assertNotNull(settings.get("folder_mode")); } diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/MetadataTestHelper.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/MetadataTestHelper.java index cdb52487..2a128c7f 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/MetadataTestHelper.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/MetadataTestHelper.java @@ -6,7 +6,9 @@ import com.cloudinary.metadata.MetadataValidation; import com.cloudinary.metadata.StringMetadataField; -public class MetadataTestHelper { +public final class MetadataTestHelper { + private MetadataTestHelper() {} + public static StringMetadataField newFieldInstance(String label, Boolean mandatory) throws Exception { StringMetadataField field = new StringMetadataField(); field.setLabel(label); diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/helpers/Feature.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/helpers/Feature.java index 2ced269c..b66bd303 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/helpers/Feature.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/helpers/Feature.java @@ -1,6 +1,8 @@ package com.cloudinary.test.helpers; -public class Feature { +public final class Feature { + private Feature() {} + public static final String ALL = "all"; public static final String DYNAMIC_FOLDERS = "dynamic_folders"; public static final String BACKEDUP_ASSETS = "backedup_assets"; From c4d7b2926fe1789237672485b6ab026415ca509f Mon Sep 17 00:00:00 2001 From: Piotr Idzik <65706193+vil02@users.noreply.github.com> Date: Mon, 21 Oct 2024 22:33:00 +0200 Subject: [PATCH 131/150] Remove unused imports --- cloudinary-core/src/main/java/com/cloudinary/AuthToken.java | 3 --- cloudinary-core/src/main/java/com/cloudinary/Search.java | 1 - cloudinary-core/src/main/java/com/cloudinary/Url.java | 1 - .../src/main/java/com/cloudinary/metadata/MetadataRule.java | 1 - .../java/com/cloudinary/strategies/AbstractApiStrategy.java | 5 ----- .../src/test/java/com/cloudinary/AuthTokenTest.java | 2 -- .../src/test/java/com/cloudinary/test/CloudinaryTest.java | 1 - .../src/main/java/com/cloudinary/http5/ApiStrategy.java | 2 -- .../main/java/com/cloudinary/taglib/CloudinaryImageTag.java | 4 ---- .../main/java/com/cloudinary/taglib/CloudinaryVideoTag.java | 1 - .../java/com/cloudinary/test/AbstractAccountApiTest.java | 1 - .../main/java/com/cloudinary/test/AbstractSearchTest.java | 3 --- .../main/java/com/cloudinary/test/AbstractUploaderTest.java | 2 -- .../src/main/java/cloudinary/lib/PhotoUploadValidator.java | 6 ------ .../main/java/cloudinary/controllers/PhotoController.java | 1 - .../src/main/java/cloudinary/lib/PhotoUploadValidator.java | 6 ------ 16 files changed, 40 deletions(-) diff --git a/cloudinary-core/src/main/java/com/cloudinary/AuthToken.java b/cloudinary-core/src/main/java/com/cloudinary/AuthToken.java index aa8cf213..a5114dd3 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/AuthToken.java +++ b/cloudinary-core/src/main/java/com/cloudinary/AuthToken.java @@ -5,13 +5,10 @@ import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; import java.nio.charset.Charset; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.util.*; -import java.util.regex.Matcher; import java.util.regex.Pattern; /** diff --git a/cloudinary-core/src/main/java/com/cloudinary/Search.java b/cloudinary-core/src/main/java/com/cloudinary/Search.java index 2ba3ac8b..369830c6 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Search.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Search.java @@ -6,7 +6,6 @@ import com.cloudinary.utils.StringUtils; import org.cloudinary.json.JSONObject; -import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; diff --git a/cloudinary-core/src/main/java/com/cloudinary/Url.java b/cloudinary-core/src/main/java/com/cloudinary/Url.java index 6517bd28..5365c996 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Url.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Url.java @@ -13,7 +13,6 @@ import java.util.regex.Pattern; import java.util.zip.CRC32; -import com.cloudinary.utils.Analytics; import com.cloudinary.utils.Base64Coder; import com.cloudinary.utils.ObjectUtils; import com.cloudinary.utils.StringUtils; diff --git a/cloudinary-core/src/main/java/com/cloudinary/metadata/MetadataRule.java b/cloudinary-core/src/main/java/com/cloudinary/metadata/MetadataRule.java index 65edbed4..4df82ded 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/metadata/MetadataRule.java +++ b/cloudinary-core/src/main/java/com/cloudinary/metadata/MetadataRule.java @@ -2,7 +2,6 @@ import com.cloudinary.utils.ObjectUtils; -import java.util.ArrayList; import java.util.HashMap; import java.util.Map; diff --git a/cloudinary-core/src/main/java/com/cloudinary/strategies/AbstractApiStrategy.java b/cloudinary-core/src/main/java/com/cloudinary/strategies/AbstractApiStrategy.java index 8878bf2c..0342f5bc 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/strategies/AbstractApiStrategy.java +++ b/cloudinary-core/src/main/java/com/cloudinary/strategies/AbstractApiStrategy.java @@ -2,12 +2,7 @@ import com.cloudinary.Api; import com.cloudinary.Api.HttpMethod; -import com.cloudinary.SmartUrlEncoder; import com.cloudinary.api.ApiResponse; -import com.cloudinary.utils.Base64Coder; -import com.cloudinary.utils.ObjectUtils; -import com.cloudinary.utils.StringUtils; -import java.util.Arrays; import java.util.Map; diff --git a/cloudinary-core/src/test/java/com/cloudinary/AuthTokenTest.java b/cloudinary-core/src/test/java/com/cloudinary/AuthTokenTest.java index 468c43bb..49fd8d35 100644 --- a/cloudinary-core/src/test/java/com/cloudinary/AuthTokenTest.java +++ b/cloudinary-core/src/test/java/com/cloudinary/AuthTokenTest.java @@ -1,6 +1,5 @@ package com.cloudinary; -import com.cloudinary.utils.Analytics; import com.cloudinary.utils.ObjectUtils; import org.hamcrest.CoreMatchers; @@ -11,7 +10,6 @@ import org.junit.Test; import org.junit.rules.TestName; -import java.io.UnsupportedEncodingException; import java.util.Calendar; import java.util.Collections; import java.util.Map; diff --git a/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java b/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java index 9e436183..b43a2bc8 100644 --- a/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java +++ b/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java @@ -18,7 +18,6 @@ import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.lang.reflect.Type; -import java.lang.reflect.ParameterizedType; import java.net.URI; import java.net.URISyntaxException; import java.net.URLDecoder; diff --git a/cloudinary-http5/src/main/java/com/cloudinary/http5/ApiStrategy.java b/cloudinary-http5/src/main/java/com/cloudinary/http5/ApiStrategy.java index 2852225d..40171489 100644 --- a/cloudinary-http5/src/main/java/com/cloudinary/http5/ApiStrategy.java +++ b/cloudinary-http5/src/main/java/com/cloudinary/http5/ApiStrategy.java @@ -7,7 +7,6 @@ import com.cloudinary.http5.api.Response; import com.cloudinary.strategies.AbstractApiStrategy; import com.cloudinary.utils.ObjectUtils; -import com.cloudinary.utils.StringUtils; import org.apache.hc.client5.http.classic.methods.*; import org.apache.hc.client5.http.entity.UrlEncodedFormEntity; import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; @@ -25,7 +24,6 @@ import java.lang.reflect.Constructor; import java.net.URISyntaxException; import java.nio.charset.StandardCharsets; -import java.util.Arrays; import java.util.List; import java.util.Map; diff --git a/cloudinary-taglib/src/main/java/com/cloudinary/taglib/CloudinaryImageTag.java b/cloudinary-taglib/src/main/java/com/cloudinary/taglib/CloudinaryImageTag.java index 2de25e3b..8b253533 100644 --- a/cloudinary-taglib/src/main/java/com/cloudinary/taglib/CloudinaryImageTag.java +++ b/cloudinary-taglib/src/main/java/com/cloudinary/taglib/CloudinaryImageTag.java @@ -4,12 +4,8 @@ import java.util.HashMap; import java.util.Map; -import javax.servlet.ServletRequest; import javax.servlet.jsp.JspException; import javax.servlet.jsp.JspWriter; -import javax.servlet.jsp.PageContext; -import javax.servlet.jsp.tagext.DynamicAttributes; -import javax.servlet.jsp.tagext.SimpleTagSupport; import com.cloudinary.*; diff --git a/cloudinary-taglib/src/main/java/com/cloudinary/taglib/CloudinaryVideoTag.java b/cloudinary-taglib/src/main/java/com/cloudinary/taglib/CloudinaryVideoTag.java index 9ed803ee..ec2adb54 100644 --- a/cloudinary-taglib/src/main/java/com/cloudinary/taglib/CloudinaryVideoTag.java +++ b/cloudinary-taglib/src/main/java/com/cloudinary/taglib/CloudinaryVideoTag.java @@ -1,7 +1,6 @@ package com.cloudinary.taglib; import java.io.IOException; -import java.util.HashMap; import java.util.Map; import javax.servlet.jsp.JspException; diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractAccountApiTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractAccountApiTest.java index 5b8e9633..7852f96b 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractAccountApiTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractAccountApiTest.java @@ -15,7 +15,6 @@ import static java.util.Collections.singletonMap; import static junit.framework.TestCase.assertTrue; import static org.junit.Assert.*; -import static org.junit.Assume.assumeTrue; public abstract class AbstractAccountApiTest extends MockableTest { private static Random rand = new Random(); diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractSearchTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractSearchTest.java index 5e30d26b..e6bf5d6e 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractSearchTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractSearchTest.java @@ -1,9 +1,7 @@ package com.cloudinary.test; import com.cloudinary.Cloudinary; -import com.cloudinary.Configuration; import com.cloudinary.Search; -import com.cloudinary.api.ApiResponse; import com.cloudinary.utils.ObjectUtils; import org.junit.*; import org.junit.rules.TestName; @@ -13,7 +11,6 @@ import static org.hamcrest.Matchers.hasEntry; import static org.hamcrest.Matchers.hasItem; -import static org.hamcrest.core.AllOf.allOf; import static org.junit.Assert.*; import static org.junit.Assume.assumeNotNull; diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java index 19098f6c..5de797fa 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java @@ -1,7 +1,6 @@ package com.cloudinary.test; import com.cloudinary.*; -import com.cloudinary.api.ApiResponse; import com.cloudinary.metadata.StringMetadataField; import com.cloudinary.test.rules.RetryRule; import com.cloudinary.utils.ObjectUtils; @@ -13,7 +12,6 @@ import java.io.*; import java.net.HttpURLConnection; import java.net.URL; -import java.net.URLEncoder; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.*; diff --git a/samples/photo_album/src/main/java/cloudinary/lib/PhotoUploadValidator.java b/samples/photo_album/src/main/java/cloudinary/lib/PhotoUploadValidator.java index 2bcdc56d..0a389e02 100644 --- a/samples/photo_album/src/main/java/cloudinary/lib/PhotoUploadValidator.java +++ b/samples/photo_album/src/main/java/cloudinary/lib/PhotoUploadValidator.java @@ -1,16 +1,10 @@ package cloudinary.lib; import cloudinary.models.PhotoUpload; -import com.cloudinary.Cloudinary; -import com.cloudinary.Singleton; import org.springframework.validation.Errors; import org.springframework.validation.ValidationUtils; import org.springframework.validation.Validator; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - public class PhotoUploadValidator implements Validator { public boolean supports(Class clazz) { return PhotoUpload.class.equals(clazz); diff --git a/samples/photo_album_gae/src/main/java/cloudinary/controllers/PhotoController.java b/samples/photo_album_gae/src/main/java/cloudinary/controllers/PhotoController.java index 53e8b537..7a6438a8 100644 --- a/samples/photo_album_gae/src/main/java/cloudinary/controllers/PhotoController.java +++ b/samples/photo_album_gae/src/main/java/cloudinary/controllers/PhotoController.java @@ -2,7 +2,6 @@ import cloudinary.lib.PhotoUploadValidator; import cloudinary.models.PhotoUpload; -import com.cloudinary.Cloudinary; import com.cloudinary.utils.ObjectUtils; import com.cloudinary.Singleton; import org.springframework.stereotype.Controller; diff --git a/samples/photo_album_gae/src/main/java/cloudinary/lib/PhotoUploadValidator.java b/samples/photo_album_gae/src/main/java/cloudinary/lib/PhotoUploadValidator.java index 2bcdc56d..0a389e02 100644 --- a/samples/photo_album_gae/src/main/java/cloudinary/lib/PhotoUploadValidator.java +++ b/samples/photo_album_gae/src/main/java/cloudinary/lib/PhotoUploadValidator.java @@ -1,16 +1,10 @@ package cloudinary.lib; import cloudinary.models.PhotoUpload; -import com.cloudinary.Cloudinary; -import com.cloudinary.Singleton; import org.springframework.validation.Errors; import org.springframework.validation.ValidationUtils; import org.springframework.validation.Validator; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - public class PhotoUploadValidator implements Validator { public boolean supports(Class clazz) { return PhotoUpload.class.equals(clazz); From 3a0e000b4fd72dd6833e4bbba0500532fb31ed4e Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Thu, 16 Jan 2025 11:00:49 +0200 Subject: [PATCH 132/150] Fix upload preset tests --- cloudinary-core/src/main/java/com/cloudinary/Api.java | 4 ++-- .../src/main/java/com/cloudinary/test/AbstractApiTest.java | 6 ++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/cloudinary-core/src/main/java/com/cloudinary/Api.java b/cloudinary-core/src/main/java/com/cloudinary/Api.java index 9dbacde9..d09df997 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Api.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Api.java @@ -338,7 +338,7 @@ public ApiResponse updateUploadPreset(String name, Map options) throws Exception if (options == null) options = ObjectUtils.emptyMap(); Map params = Util.buildUploadParams(options); Util.clearEmpty(params); - params.putAll(ObjectUtils.only(options, "unsigned", "disallow_public_id", "live")); + params.putAll(ObjectUtils.only(options, "unsigned", "disallow_public_id")); return callApi(HttpMethod.PUT, Arrays.asList("upload_presets", name), params, options); } @@ -346,7 +346,7 @@ public ApiResponse createUploadPreset(Map options) throws Exception { if (options == null) options = ObjectUtils.emptyMap(); Map params = Util.buildUploadParams(options); Util.clearEmpty(params); - params.putAll(ObjectUtils.only(options, "name", "unsigned", "disallow_public_id", "live")); + params.putAll(ObjectUtils.only(options, "name", "unsigned", "disallow_public_id")); return callApi(HttpMethod.POST, Arrays.asList("upload_presets"), params, options); } diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java index e5ae3703..9ec8746f 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java @@ -825,14 +825,13 @@ public void testGetUploadPreset() throws Exception { String[] tags = {"a", "b", "c"}; Map context = ObjectUtils.asMap("a", "b", "c", "d"); Map result = api.createUploadPreset(ObjectUtils.asMap("unsigned", true, "folder", "folder", "transformation", EXPLICIT_TRANSFORMATION, "tags", tags, "context", - context, "live", true, "use_asset_folder_as_public_id_prefix", true)); + context, "use_asset_folder_as_public_id_prefix", true)); String name = result.get("name").toString(); Map preset = api.uploadPreset(name, ObjectUtils.emptyMap()); assertEquals(preset.get("name"), name); assertEquals(Boolean.TRUE, preset.get("unsigned")); Map settings = (Map) preset.get("settings"); assertEquals(settings.get("folder"), "folder"); - assertEquals(settings.get("live"), Boolean.TRUE); assertEquals(settings.get("use_asset_folder_as_public_id_prefix"), true); Map outTransformation = (Map) ((java.util.ArrayList) settings.get("transformation")).get(0); assertEquals(outTransformation.get("width"), 100); @@ -866,13 +865,12 @@ public void testUpdateUploadPreset() throws Exception { String name = api.createUploadPreset(ObjectUtils.asMap("folder", "folder")).get("name").toString(); Map preset = api.uploadPreset(name, ObjectUtils.emptyMap()); Map settings = (Map) preset.get("settings"); - settings.putAll(ObjectUtils.asMap("colors", true, "unsigned", true, "disallow_public_id", true, "live", true, "eval",AbstractUploaderTest.SRC_TEST_EVAL)); + settings.putAll(ObjectUtils.asMap("colors", true, "unsigned", true, "disallow_public_id", true, "eval",AbstractUploaderTest.SRC_TEST_EVAL)); api.updateUploadPreset(name, settings); settings.remove("unsigned"); preset = api.uploadPreset(name, ObjectUtils.emptyMap()); assertEquals(name, preset.get("name")); assertEquals(Boolean.TRUE, preset.get("unsigned")); - assertEquals(settings.get("live"), Boolean.TRUE); assertEquals(settings, preset.get("settings")); api.deleteUploadPreset(name, ObjectUtils.emptyMap()); From 0f456e8a14b2f3957bc8fdd75373446bd6927144 Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Thu, 16 Jan 2025 12:51:41 +0200 Subject: [PATCH 133/150] Update Cloudinary constructor --- .../main/java/com/cloudinary/Cloudinary.java | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java index 9bdbe122..b802d26d 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java @@ -85,22 +85,21 @@ private void loadStrategies() { } public Cloudinary(Map config) { - this.config = new Configuration(config); - loadStrategies(); + this(new Configuration(config)); } public Cloudinary(String cloudinaryUrl) { - this.config = Configuration.from(cloudinaryUrl); - loadStrategies(); + this(Configuration.from(cloudinaryUrl)); } public Cloudinary() { - String cloudinaryUrl = System.getProperty("CLOUDINARY_URL", System.getenv("CLOUDINARY_URL")); - if (cloudinaryUrl != null) { - this.config = Configuration.from(cloudinaryUrl); - } else { - this.config = new Configuration(); - } + this(System.getProperty("CLOUDINARY_URL", System.getenv("CLOUDINARY_URL")) != null + ? Configuration.from(System.getProperty("CLOUDINARY_URL", System.getenv("CLOUDINARY_URL"))) + : new Configuration()); + } + + public Cloudinary(Configuration config) { + this.config = config; loadStrategies(); } From fad1ed50956b21206706750c06f5f4d38c5cb82d Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Thu, 16 Jan 2025 12:52:01 +0200 Subject: [PATCH 134/150] Fix and test register upload + api strategies --- .../src/main/java/com/cloudinary/Cloudinary.java | 6 +++--- .../java/com/cloudinary/test/CloudinaryTest.java | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java index b802d26d..f70f8965 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java @@ -20,7 +20,7 @@ @SuppressWarnings({"rawtypes", "unchecked"}) public class Cloudinary { - private static List UPLOAD_STRATEGIES = new ArrayList(Arrays.asList( + public static List UPLOAD_STRATEGIES = new ArrayList(Arrays.asList( "com.cloudinary.android.UploaderStrategy", "com.cloudinary.http5.UploaderStrategy")); public static List API_STRATEGIES = new ArrayList(Arrays.asList( @@ -59,14 +59,14 @@ public SearchFolders searchFolders() { public static void registerUploaderStrategy(String className) { if (!UPLOAD_STRATEGIES.contains(className)) { - UPLOAD_STRATEGIES.add(className); + UPLOAD_STRATEGIES.add(0, className); } } public static void registerAPIStrategy(String className) { if (!API_STRATEGIES.contains(className)) { - API_STRATEGIES.add(className); + API_STRATEGIES.add(0, className); } } diff --git a/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java b/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java index b43a2bc8..18064976 100644 --- a/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java +++ b/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java @@ -1464,6 +1464,20 @@ public void testDownloadBackedupAsset() throws UnsupportedEncodingException, URI assertNotNull(params.get("timestamp")); } + @Test + public void testRegisterUploaderStrategy() { + String className = "myUploadStrategy"; + Cloudinary.registerUploaderStrategy(className); + assertEquals(className, Cloudinary.UPLOAD_STRATEGIES.get(0)); + } + + @Test + public void testRegisterApiStrategy() { + String className = "myApiStrategy"; + Cloudinary.registerAPIStrategy(className); + assertEquals(className, Cloudinary.API_STRATEGIES.get(0)); + } + private void assertFieldsEqual(Object a, Object b) throws IllegalAccessException { assertEquals("Two objects must be the same class", a.getClass(), b.getClass()); Field[] fields = a.getClass().getFields(); From 98f0260ce1b4e0fc965ce16c09e8956a35a2e022 Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Mon, 20 Jan 2025 08:10:00 +0200 Subject: [PATCH 135/150] Fix Http client 5.0 init (#369) --- .../com/cloudinary/http5/ApiStrategy.java | 38 +++++++++++++++++-- .../java/com/cloudinary/test/ApiTest.java | 38 ++++++++++++++++++- 2 files changed, 71 insertions(+), 5 deletions(-) diff --git a/cloudinary-http5/src/main/java/com/cloudinary/http5/ApiStrategy.java b/cloudinary-http5/src/main/java/com/cloudinary/http5/ApiStrategy.java index 40171489..9c0145e9 100644 --- a/cloudinary-http5/src/main/java/com/cloudinary/http5/ApiStrategy.java +++ b/cloudinary-http5/src/main/java/com/cloudinary/http5/ApiStrategy.java @@ -8,15 +8,20 @@ import com.cloudinary.strategies.AbstractApiStrategy; import com.cloudinary.utils.ObjectUtils; import org.apache.hc.client5.http.classic.methods.*; +import org.apache.hc.client5.http.config.RequestConfig; import org.apache.hc.client5.http.entity.UrlEncodedFormEntity; import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; +import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.client5.http.io.HttpClientConnectionManager; import org.apache.hc.core5.http.HttpEntity; +import org.apache.hc.core5.http.HttpHost; import org.apache.hc.core5.http.NameValuePair; import org.apache.hc.core5.http.io.entity.EntityUtils; import org.apache.hc.core5.http.io.entity.StringEntity; import org.apache.hc.core5.net.URIBuilder; +import org.apache.hc.core5.util.Timeout; import org.cloudinary.json.JSONException; import org.cloudinary.json.JSONObject; @@ -36,15 +41,42 @@ public class ApiStrategy extends AbstractApiStrategy { private CloseableHttpClient client; - @Override public void init(Api api) { super.init(api); - this.client = HttpClients.custom() - .setUserAgent(this.api.cloudinary.getUserAgent() + " ApacheHttpClient/" + APACHE_HTTP_CLIENT_VERSION) + HttpClientBuilder clientBuilder = HttpClients.custom(); + clientBuilder.useSystemProperties().setUserAgent(this.api.cloudinary.getUserAgent() + " ApacheHttpClient/" + APACHE_HTTP_CLIENT_VERSION); + + HttpClientConnectionManager connectionManager = (HttpClientConnectionManager) api.cloudinary.config.properties.get("connectionManager"); + if (connectionManager != null) { + clientBuilder.setConnectionManager(connectionManager); + } + + RequestConfig requestConfig = buildRequestConfig(); + + client = clientBuilder + .setDefaultRequestConfig(requestConfig) .build(); } + public RequestConfig buildRequestConfig() { + RequestConfig.Builder requestConfigBuilder = RequestConfig.custom(); + + if (api.cloudinary.config.proxyHost != null && api.cloudinary.config.proxyPort != 0) { + HttpHost proxy = new HttpHost(api.cloudinary.config.proxyHost, api.cloudinary.config.proxyPort); + requestConfigBuilder.setProxy(proxy); + } + + int timeout = this.api.cloudinary.config.timeout; + if (timeout > 0) { + requestConfigBuilder.setResponseTimeout(Timeout.ofSeconds(timeout)) + .setConnectionRequestTimeout(Timeout.ofSeconds(timeout)) + .setConnectTimeout(Timeout.ofSeconds(timeout)); + } + + return requestConfigBuilder.build(); + } + @SuppressWarnings({"rawtypes", "unchecked"}) public ApiResponse callApi(Api.HttpMethod method, String apiUrl, Map params, Map options, String autorizationHeader) throws Exception { HttpUriRequestBase request = prepareRequest(method, apiUrl, params, options); diff --git a/cloudinary-http5/src/test/java/com/cloudinary/test/ApiTest.java b/cloudinary-http5/src/test/java/com/cloudinary/test/ApiTest.java index a2f3c89f..4735d89f 100644 --- a/cloudinary-http5/src/test/java/com/cloudinary/test/ApiTest.java +++ b/cloudinary-http5/src/test/java/com/cloudinary/test/ApiTest.java @@ -1,15 +1,50 @@ package com.cloudinary.test; +import com.cloudinary.Cloudinary; import com.cloudinary.api.ApiResponse; +import com.cloudinary.http5.ApiStrategy; import com.cloudinary.utils.ObjectUtils; +import org.apache.hc.client5.http.config.RequestConfig; +import org.apache.hc.core5.http.HttpHost; import org.apache.hc.core5.util.Timeout; import org.junit.Test; import org.junit.experimental.categories.Category; + import java.util.Map; public class ApiTest extends AbstractApiTest { + @Test + public void testBuildRequestConfig_withProxyAndTimeout() { + Cloudinary cloudinary = new Cloudinary("cloudinary://test:test@test.com"); + cloudinary.config.proxyHost = "127.0.0.1"; + cloudinary.config.proxyPort = 8080; + cloudinary.config.timeout = 15; + + RequestConfig requestConfig = ((ApiStrategy)cloudinary.api().getStrategy()).buildRequestConfig(); + + assert(requestConfig.getProxy() != null); + HttpHost proxy = requestConfig.getProxy(); + assert("127.0.0.1" == proxy.getHostName()); + assert(8080 == proxy.getPort()); + + assert(15000 == requestConfig.getConnectionRequestTimeout().toMilliseconds()); + assert(15000 == requestConfig.getResponseTimeout().toMilliseconds()); + } + + @Test + public void testBuildRequestConfig_withoutProxy() { + Cloudinary cloudinary = new Cloudinary("cloudinary://test:test@test.com"); + cloudinary.config.timeout = 10; + + RequestConfig requestConfig = ((ApiStrategy)cloudinary.api().getStrategy()).buildRequestConfig(); + + assert(requestConfig.getProxy() == null); + assert(10000 == requestConfig.getConnectionRequestTimeout().toMilliseconds()); + assert(10000 == requestConfig.getResponseTimeout().toMilliseconds()); + } + @Category(TimeoutTest.class) @Test(expected = Exception.class) public void testConnectTimeoutParameter() throws Exception { @@ -41,5 +76,4 @@ public void testTimeoutParameter() throws Exception { throw new Exception("Socket timeout"); } } -} - +} \ No newline at end of file From 209037e99016bb76067a52cea33e2098502ac868 Mon Sep 17 00:00:00 2001 From: Adi Mizrahi Date: Mon, 20 Jan 2025 12:17:20 +0200 Subject: [PATCH 136/150] Version 2.1.0 --- CHANGELOG.md | 8 ++++++++ README.md | 4 ++-- .../src/main/java/com/cloudinary/Cloudinary.java | 2 +- gradle.properties | 2 +- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bc13fee5..ffe151ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +2.1.0 / 2025-01-20 +================== + +* Fix Http client proxy +* Fix Http client system properties support +* Add Cloudinary constructor for `Configuration` +* Fix Register strategy functions + 2.0.0 / 2024-09-29 ================== diff --git a/README.md b/README.md index 4e44ba97..74e77daa 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ For the complete documentation, see the [Java SDK Guide](https://cloudinary.com/ | SDK Version | Java 6+ | Java 8 | |----------------|---------|--------| | 1.1.0 - 1.39.0 | V | | -| 2.0.0 | | V | +| 2.0.0+ | | V | @@ -39,7 +39,7 @@ The cloudinary_java library is available in [Maven Central](https://mvnrepositor com.cloudinary cloudinary-http45 - 2.0.0 + 2.1.0 ``` diff --git a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java index f70f8965..aa156ec2 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java @@ -32,7 +32,7 @@ public class Cloudinary { public final static String AKAMAI_SHARED_CDN = "res.cloudinary.com"; public final static String SHARED_CDN = AKAMAI_SHARED_CDN; - public final static String VERSION = "2.0.0"; + public final static String VERSION = "2.1.0"; static String USER_AGENT_PREFIX = "CloudinaryJava"; public final static String USER_AGENT_JAVA_VERSION = "(Java " + System.getProperty("java.version") + ")"; diff --git a/gradle.properties b/gradle.properties index c15a7578..6ce82a60 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,7 +13,7 @@ developerEmail=info@cloudinary.com # These two properties must use these exact names to be compatible with 'gradle install' plugin. group=com.cloudinary -version=2.0.0 +version=2.1.0 gnsp.disableApplyOnlyOnRootProjectEnforcement=true From 4e7d91f77ae8f4a9c45e6439dac39caafde72815 Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Mon, 27 Jan 2025 08:06:28 +0200 Subject: [PATCH 137/150] Add delete resources by assetids --- .../src/main/java/com/cloudinary/Api.java | 7 +++++++ .../java/com/cloudinary/test/AbstractApiTest.java | 14 ++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/cloudinary-core/src/main/java/com/cloudinary/Api.java b/cloudinary-core/src/main/java/com/cloudinary/Api.java index d09df997..0885ab13 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Api.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Api.java @@ -240,6 +240,13 @@ public ApiResponse deleteResources(Iterable publicIds, Map options) thro return callApi(HttpMethod.DELETE, Arrays.asList("resources", resourceType, type), params, options); } + public ApiResponse deleteResourcesByAssetIds(Iterable assetIds, Map options) throws Exception { + if (options == null) options = ObjectUtils.emptyMap(); + Map params = ObjectUtils.only(options, "keep_original", "invalidate", "next_cursor", "transformations"); + params.put("asset_ids", assetIds); + return callApi(HttpMethod.DELETE, Arrays.asList("resources"), params, options); + } + public ApiResponse deleteDerivedByTransformation(Iterable publicIds, List transformations, Map options) throws Exception { if (options == null) options = ObjectUtils.emptyMap(); String resourceType = ObjectUtils.asString(options.get("resource_type"), "image"); diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java index 9ec8746f..4a73ff73 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java @@ -464,6 +464,20 @@ public void test09DeleteResources() throws Exception { api.resource(public_id, ObjectUtils.emptyMap()); } + @Test(expected = NotFound.class) + public void test10DeleteResourcesByAssetsIds() throws Exception { + String public_id = "api_,test4" + SUFFIX; + cloudinary.uploader().upload(SRC_TEST_IMAGE, ObjectUtils.asMap("public_id", public_id, "tags", UPLOAD_TAGS)); + Map resource = api.resource(public_id, ObjectUtils.emptyMap()); + assertNotNull(resource); + String assetId = (String)resource.get("asset_id"); + ApiResponse response = api.deleteResourcesByAssetIds(Arrays.asList(assetId), ObjectUtils.emptyMap()); + assertNotNull(response); + assertNotNull(response.get("deleted")); + assertNotNull(response.get("deleted_counts")); + api.resource(public_id, ObjectUtils.emptyMap()); + } + @Test(expected = NotFound.class) public void test09aDeleteResourcesByPrefix() throws Exception { // should allow deleting resources From a8284ebc8f0ae98760405d6454706e97a341529f Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Tue, 28 Jan 2025 17:15:18 +0200 Subject: [PATCH 138/150] Add allow dynamic list to List Metadata field --- .../java/com/cloudinary/metadata/MetadataField.java | 7 +++++++ .../test/AbstractStructuredMetadataTest.java | 10 ++++++++++ 2 files changed, 17 insertions(+) diff --git a/cloudinary-core/src/main/java/com/cloudinary/metadata/MetadataField.java b/cloudinary-core/src/main/java/com/cloudinary/metadata/MetadataField.java index 4f3bdf33..7fe81c43 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/metadata/MetadataField.java +++ b/cloudinary-core/src/main/java/com/cloudinary/metadata/MetadataField.java @@ -18,6 +18,7 @@ public class MetadataField extends JSONObject { public static final String VALIDATION = "validation"; public static final String RESTRICTIONS = "restrictions"; public static final String DEFAULT_DISABLED = "default_disabled"; + public static final String ALLOW_DYNAMIC_LIST_VALUES = "allow_dynamic_list_values"; public MetadataField(MetadataFieldType type) { put(TYPE, type.toString()); @@ -148,4 +149,10 @@ public void setRestrictions(Restrictions restrictions) { public void setDefaultDisabled(Boolean disabled) { put(DEFAULT_DISABLED, disabled); } + + /** + * Set the value indicating whether the dynamic list values should allow + * @param allowDynamicListValues The value to set. + */ + public void setAllowDynamicListValues(Boolean allowDynamicListValues) {put(ALLOW_DYNAMIC_LIST_VALUES, allowDynamicListValues);} } \ No newline at end of file diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractStructuredMetadataTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractStructuredMetadataTest.java index 241ac47d..60467685 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractStructuredMetadataTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractStructuredMetadataTest.java @@ -73,6 +73,15 @@ public void testCreateMetadata() throws Exception { assertEquals(setField.getLabel(), result.get("label")); } + @Test + public void testCreateSetMetadataWithAllowDynamicListValues() throws Exception { + SetMetadataField setField = createSetField("testCreateMetadata_2"); + ApiResponse result = cloudinary.api().addMetadataField(setField); + assertNotNull(result); + assertEquals(setField.getLabel(), result.get("label")); + assertEquals(true, result.get("allow_dynamic_list_values")); + } + @Test public void testFieldRestrictions() throws Exception { StringMetadataField stringField = newFieldInstance("testCreateMetadata_3", true); @@ -367,6 +376,7 @@ private SetMetadataField createSetField(String labelPrefix) { String label = labelPrefix + "_" + SUFFIX; setField.setLabel(label); setField.setMandatory(false); + setField.setAllowDynamicListValues(true); setField.setValidation(new MetadataValidation.StringLength(3, 99)); setField.setDefaultValue(Arrays.asList("id2", "id3")); setField.setValidation(null); From 61a5c905e84a24af5e328268b8444e7290b2f27e Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Wed, 29 Jan 2025 15:42:59 +0200 Subject: [PATCH 139/150] Add restore by asset ids api call --- .../src/main/java/com/cloudinary/Api.java | 8 ++++++ .../com/cloudinary/test/AbstractApiTest.java | 26 +++++++++++++++++++ .../test/AbstractStructuredMetadataTest.java | 2 +- 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/cloudinary-core/src/main/java/com/cloudinary/Api.java b/cloudinary-core/src/main/java/com/cloudinary/Api.java index 0885ab13..0cbab208 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Api.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Api.java @@ -393,6 +393,14 @@ public ApiResponse restore(Iterable publicIds, Map options) throws Excep return response; } + public ApiResponse restoreByAssetIds(Iterable assetIds, Map options) throws Exception { + if (options == null) + options = ObjectUtils.emptyMap(); + Map params = new HashMap(); + params.put("asset_ids", assetIds); + return callApi(HttpMethod.POST, Arrays.asList("resources", "restore"), params, options); + } + public ApiResponse uploadMappings(Map options) throws Exception { if (options == null) options = ObjectUtils.emptyMap(); diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java index 4a73ff73..5c854d75 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java @@ -971,6 +971,32 @@ public void testRestore() throws Exception { assertEquals(resource.get("bytes"), 3381); } + @Test + public void testRestoreByAssetIds() throws Exception { + + // Upload + cloudinary.uploader().upload(SRC_TEST_IMAGE, + ObjectUtils.asMap("public_id", API_TEST_RESTORE, "backup", true, "tags", UPLOAD_TAGS)); + Map resource = api.resource(API_TEST_RESTORE, ObjectUtils.emptyMap()); + assertEquals(resource.get("bytes"), 3381); + + //Delete + api.deleteResources(Collections.singletonList(API_TEST_RESTORE), ObjectUtils.emptyMap()); + resource = api.resource(API_TEST_RESTORE, ObjectUtils.emptyMap()); + String assetId = (String) resource.get("asset_id"); + assertEquals(resource.get("bytes"), 0); + assertNotNull(assetId); + assertTrue((Boolean) resource.get("placeholder")); + + //Restore + Map response = api.restoreByAssetIds(Collections.singletonList(assetId), ObjectUtils.emptyMap()); + Map info = (Map) response.get(assetId); + assertNotNull(info); + assertEquals(info.get("bytes"), 3381); + resource = api.resource(API_TEST_RESTORE, ObjectUtils.emptyMap()); + assertEquals(resource.get("bytes"), 3381); + } + @Test public void testRestoreDifferentVersionsOfDeletedAsset() throws Exception { final String TEST_RESOURCE_PUBLIC_ID = "api_test_restore_different_versions_single_asset" + SUFFIX; diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractStructuredMetadataTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractStructuredMetadataTest.java index 60467685..b1137fb4 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractStructuredMetadataTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractStructuredMetadataTest.java @@ -75,7 +75,7 @@ public void testCreateMetadata() throws Exception { @Test public void testCreateSetMetadataWithAllowDynamicListValues() throws Exception { - SetMetadataField setField = createSetField("testCreateMetadata_2"); + SetMetadataField setField = createSetField("testCreateMetadata_4"); ApiResponse result = cloudinary.api().addMetadataField(setField); assertNotNull(result); assertEquals(setField.getLabel(), result.get("label")); From c646ad486e1beb156e94da729da9da3550bbe891 Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Thu, 30 Jan 2025 14:36:53 +0200 Subject: [PATCH 140/150] Fix Uploader strategy --- .../cloudinary/http5/UploaderStrategy.java | 37 ++++++++++++++++++- .../java/com/cloudinary/test/ApiTest.java | 27 +++++++++++++- 2 files changed, 60 insertions(+), 4 deletions(-) diff --git a/cloudinary-http5/src/main/java/com/cloudinary/http5/UploaderStrategy.java b/cloudinary-http5/src/main/java/com/cloudinary/http5/UploaderStrategy.java index 5f87cbd8..589dff5b 100644 --- a/cloudinary-http5/src/main/java/com/cloudinary/http5/UploaderStrategy.java +++ b/cloudinary-http5/src/main/java/com/cloudinary/http5/UploaderStrategy.java @@ -8,16 +8,21 @@ import com.cloudinary.utils.StringUtils; import org.apache.hc.client5.http.classic.methods.HttpPost; import org.apache.hc.client5.http.classic.methods.HttpUriRequestBase; +import org.apache.hc.client5.http.config.RequestConfig; import org.apache.hc.client5.http.entity.mime.ByteArrayBody; import org.apache.hc.client5.http.entity.mime.FileBody; import org.apache.hc.client5.http.entity.mime.HttpMultipartMode; import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder; import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; +import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.client5.http.io.HttpClientConnectionManager; import org.apache.hc.core5.http.ContentType; +import org.apache.hc.core5.http.HttpHost; import org.apache.hc.core5.http.ParseException; import org.apache.hc.core5.http.io.entity.EntityUtils; +import org.apache.hc.core5.util.Timeout; import java.io.File; import java.io.IOException; @@ -35,11 +40,39 @@ public class UploaderStrategy extends AbstractUploaderStrategy { public void init(Uploader uploader) { super.init(uploader); - this.client = HttpClients.custom() - .setUserAgent(cloudinary().getUserAgent() + " ApacheHttpClient/" + APACHE_HTTP_CLIENT_VERSION) + HttpClientBuilder clientBuilder = HttpClients.custom(); + clientBuilder.useSystemProperties().setUserAgent(cloudinary().getUserAgent() + " ApacheHttpClient/" + APACHE_HTTP_CLIENT_VERSION); + + HttpClientConnectionManager connectionManager = (HttpClientConnectionManager) cloudinary().config.properties.get("connectionManager"); + if (connectionManager != null) { + clientBuilder.setConnectionManager(connectionManager); + } + + RequestConfig requestConfig = buildRequestConfig(); + + client = clientBuilder + .setDefaultRequestConfig(requestConfig) .build(); } + public RequestConfig buildRequestConfig() { + RequestConfig.Builder requestConfigBuilder = RequestConfig.custom(); + + if (cloudinary().config.proxyHost != null && cloudinary().config.proxyPort != 0) { + HttpHost proxy = new HttpHost(cloudinary().config.proxyHost, cloudinary().config.proxyPort); + requestConfigBuilder.setProxy(proxy); + } + + int timeout = cloudinary().config.timeout; + if (timeout > 0) { + requestConfigBuilder.setResponseTimeout(Timeout.ofSeconds(timeout)) + .setConnectionRequestTimeout(Timeout.ofSeconds(timeout)) + .setConnectTimeout(Timeout.ofSeconds(timeout)); + } + + return requestConfigBuilder.build(); + } + @SuppressWarnings({"rawtypes", "unchecked"}) @Override public Map callApi(String action, Map params, Map options, Object file, ProgressCallback progressCallback) throws IOException { diff --git a/cloudinary-http5/src/test/java/com/cloudinary/test/ApiTest.java b/cloudinary-http5/src/test/java/com/cloudinary/test/ApiTest.java index 4735d89f..53da8866 100644 --- a/cloudinary-http5/src/test/java/com/cloudinary/test/ApiTest.java +++ b/cloudinary-http5/src/test/java/com/cloudinary/test/ApiTest.java @@ -11,6 +11,9 @@ import org.junit.experimental.categories.Category; import java.util.Map; +import java.util.UUID; + +import static com.cloudinary.utils.ObjectUtils.asMap; public class ApiTest extends AbstractApiTest { @@ -48,7 +51,7 @@ public void testBuildRequestConfig_withoutProxy() { @Category(TimeoutTest.class) @Test(expected = Exception.class) public void testConnectTimeoutParameter() throws Exception { - Map options = ObjectUtils.asMap( + Map options = asMap( "max_results", 500, "connect_timeout", 0.2); @@ -65,7 +68,7 @@ public void testConnectTimeoutParameter() throws Exception { @Test(expected = Exception.class) public void testTimeoutParameter() throws Exception { // Set a very short request timeout to trigger a timeout exception - Map options = ObjectUtils.asMap( + Map options = asMap( "max_results", 500, "timeout", Timeout.ofMilliseconds(1000)); // Set the timeout to 1 second @@ -76,4 +79,24 @@ public void testTimeoutParameter() throws Exception { throw new Exception("Socket timeout"); } } + + @Category(TimeoutTest.class) + @Test(expected = Exception.class) + public void testUploaderTimeoutParameter() throws Exception { + Cloudinary cloudinary = new Cloudinary("cloudinary://test:test@test.com"); + cloudinary.config.uploadPrefix = "https://10.255.255.1"; + String publicId = UUID.randomUUID().toString(); + // Set a very short request timeout to trigger a timeout exception + Map options = asMap( + "max_results", 500, + "timeout", Timeout.ofMilliseconds(10)); // Set the timeout to 1 second + + try { + Map result = cloudinary.uploader().addContext(asMap("caption", "new caption"), new String[]{publicId, "no-such-id"}, options); + } catch (Exception e) { + // Convert IOException to SocketTimeoutException if appropriate + throw new Exception("Socket timeout"); + } + } + } \ No newline at end of file From a9e77cd2ee94b4ec8562f8c5a731accad64c0134 Mon Sep 17 00:00:00 2001 From: Adi Mizrahi Date: Sun, 2 Feb 2025 14:15:48 +0200 Subject: [PATCH 141/150] Version 2.2.0 --- CHANGELOG.md | 8 ++++++++ README.md | 2 +- .../src/main/java/com/cloudinary/Cloudinary.java | 2 +- gradle.properties | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ffe151ac..ba03059e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +2.2.0 / 2025-02-02 +================== + +* Fix Uploader strategy +* Add restore assets by asset ids +* Add allow dynamic list parameter +* Add delete resources by asset ids + 2.1.0 / 2025-01-20 ================== diff --git a/README.md b/README.md index 74e77daa..f5659de0 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ The cloudinary_java library is available in [Maven Central](https://mvnrepositor com.cloudinary cloudinary-http45 - 2.1.0 + 2.2.0 ``` diff --git a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java index aa156ec2..19c0c3b8 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java @@ -32,7 +32,7 @@ public class Cloudinary { public final static String AKAMAI_SHARED_CDN = "res.cloudinary.com"; public final static String SHARED_CDN = AKAMAI_SHARED_CDN; - public final static String VERSION = "2.1.0"; + public final static String VERSION = "2.2.0"; static String USER_AGENT_PREFIX = "CloudinaryJava"; public final static String USER_AGENT_JAVA_VERSION = "(Java " + System.getProperty("java.version") + ")"; diff --git a/gradle.properties b/gradle.properties index 6ce82a60..aaea4f1d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,7 +13,7 @@ developerEmail=info@cloudinary.com # These two properties must use these exact names to be compatible with 'gradle install' plugin. group=com.cloudinary -version=2.1.0 +version=2.2.0 gnsp.disableApplyOnlyOnRootProjectEnforcement=true From 45a218aeafd01b273d183b21264be7d8f69d1576 Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Mon, 3 Feb 2025 15:39:28 +0200 Subject: [PATCH 142/150] Add skip backup parameter to delete folder api --- .../src/main/java/com/cloudinary/Api.java | 4 +++- .../com/cloudinary/test/AbstractFoldersApiTest.java | 13 +++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/cloudinary-core/src/main/java/com/cloudinary/Api.java b/cloudinary-core/src/main/java/com/cloudinary/Api.java index 0cbab208..4a01933f 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Api.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Api.java @@ -660,8 +660,10 @@ public ApiResponse updateResourcesAccessModeByTag(String accessMode, String tag, * @throws Exception When the folder isn't empty or doesn't exist. */ public ApiResponse deleteFolder(String folder, Map options) throws Exception { + if (options == null || options.isEmpty()) options = ObjectUtils.asMap(); List uri = Arrays.asList("folders", folder); - return callApi(HttpMethod.DELETE, uri, Collections.emptyMap(), options); + Map params = ObjectUtils.only(options, "skip_backup"); + return callApi(HttpMethod.DELETE, uri, params, options); } /** diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractFoldersApiTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractFoldersApiTest.java index a0478bad..a8835046 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractFoldersApiTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractFoldersApiTest.java @@ -85,4 +85,17 @@ public void testSubFolderWithParams() throws Exception { ApiResponse result = api.deleteFolder(rootFolderName, null); assertTrue(((List) result.get("deleted")).contains(rootFolderName)); } + + @Test + public void testDeleteFolderWithSkipBackup() throws Exception { + //Create + String rootFolderName = "deleteFolderWithSkipBackup" + SUFFIX; + assertTrue((Boolean) api.createFolder(rootFolderName, null).get("success")); + + //Delete + ApiResponse result = api.deleteFolder(rootFolderName, ObjectUtils.asMap("skip_backup", "true")); + assertTrue(((List) result.get("deleted")).contains(rootFolderName)); + + + } } From bae86bc9717c8ef8f09d28c58de8966c72232540 Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Wed, 5 Feb 2025 13:00:49 +0200 Subject: [PATCH 143/150] Fix build single resource params --- .../src/main/java/com/cloudinary/Api.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/cloudinary-core/src/main/java/com/cloudinary/Api.java b/cloudinary-core/src/main/java/com/cloudinary/Api.java index 4a01933f..c84be0d6 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Api.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Api.java @@ -162,7 +162,7 @@ public ApiResponse resourceByAssetID(String assetId, Map options) throws Excepti if(options.get("fields") != null) { options.put("fields", StringUtils.join(ObjectUtils.asArray(options.get("fields")), ",")); } - Map params = ObjectUtils.only(options, "tags", "context", "moderations", "fields"); + Map params = buildResourceDetailParams(options); ApiResponse response = callApi(HttpMethod.GET, Arrays.asList("resources", assetId), params, options); return response; } @@ -209,15 +209,19 @@ public ApiResponse resource(String public_id, Map options) throws Exception { if (options == null) options = ObjectUtils.emptyMap(); String resourceType = ObjectUtils.asString(options.get("resource_type"), "image"); String type = ObjectUtils.asString(options.get("type"), "upload"); + Map params = buildResourceDetailParams(options); - ApiResponse response = callApi(HttpMethod.GET, Arrays.asList("resources", resourceType, type, public_id), - ObjectUtils.only(options, "exif", "colors", "faces", "coordinates", - "image_metadata", "pages", "phash", "max_results", "quality_analysis", "cinemagraph_analysis", - "accessibility_analysis", "versions", "media_metadata", "derived_next_cursor"), options); + ApiResponse response = callApi(HttpMethod.GET, Arrays.asList("resources", resourceType, type, public_id), params, options); return response; } + private Map buildResourceDetailParams(Map options) { + return ObjectUtils.only(options, "exif", "colors", "faces", "coordinates", + "image_metadata", "pages", "phash", "max_results", "quality_analysis", "cinemagraph_analysis", + "accessibility_analysis", "versions", "media_metadata", "derived_next_cursor"); + } + public ApiResponse update(String public_id, Map options) throws Exception { if (options == null) options = ObjectUtils.emptyMap(); String resourceType = ObjectUtils.asString(options.get("resource_type"), "image"); From 90cc3598c6f2093838dff96def7f2337f5675fcc Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Wed, 18 Jun 2025 09:09:23 +0300 Subject: [PATCH 144/150] Fix API parameters signature --- .../main/java/com/cloudinary/Cloudinary.java | 6 +-- .../java/com/cloudinary/Configuration.java | 15 ++++++ .../src/main/java/com/cloudinary/Util.java | 52 +++++++++++++------ .../signing/ApiResponseSignatureVerifier.java | 2 +- .../com/cloudinary/test/CloudinaryTest.java | 4 +- .../com/cloudinary/test/AbstractApiTest.java | 35 +++++++++++++ .../cloudinary/test/AbstractUploaderTest.java | 10 ++-- 7 files changed, 97 insertions(+), 27 deletions(-) diff --git a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java index 19c0c3b8..bbb07e36 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java @@ -130,8 +130,8 @@ public String signedPreloadedImage(Map result) { + (result.containsKey("format") ? "." + result.get("format") : "") + "#" + result.get("signature"); } - public String apiSignRequest(Map paramsToSign, String apiSecret) { - return Util.produceSignature(paramsToSign, apiSecret, config.signatureAlgorithm); + public String apiSignRequest(Map paramsToSign, String apiSecret, int signatureVersion) { + return Util.produceSignature(paramsToSign, apiSecret, config.signatureAlgorithm, signatureVersion); } /** @@ -206,7 +206,7 @@ public void signRequest(Map params, Map options) if (apiSecret == null) throw new IllegalArgumentException("Must supply api_secret"); Util.clearEmpty(params); - params.put("signature", this.apiSignRequest(params, apiSecret)); + params.put("signature", this.apiSignRequest(params, apiSecret, this.config.signatureVersion)); params.put("api_key", apiKey); } diff --git a/cloudinary-core/src/main/java/com/cloudinary/Configuration.java b/cloudinary-core/src/main/java/com/cloudinary/Configuration.java index 07280d89..7586ae46 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Configuration.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Configuration.java @@ -21,6 +21,7 @@ public class Configuration { public final static String USER_AGENT = "cld-android-" + VERSION; public static final boolean DEFAULT_IS_LONG_SIGNATURE = false; public static final SignatureAlgorithm DEFAULT_SIGNATURE_ALGORITHM = SignatureAlgorithm.SHA1; + public static final int DEFAULT_SIGNATURE_VERSION = 2; private static final String CONFIG_PROP_SIGNATURE_ALGORITHM = "signature_algorithm"; @@ -48,6 +49,7 @@ public class Configuration { public boolean forceVersion = true; public boolean longUrlSignature = DEFAULT_IS_LONG_SIGNATURE; public SignatureAlgorithm signatureAlgorithm = DEFAULT_SIGNATURE_ALGORITHM; + public int signatureVersion = DEFAULT_SIGNATURE_VERSION; public String oauthToken = null; public Boolean analytics; public Configuration() { @@ -75,6 +77,7 @@ private Configuration( boolean forceVersion, boolean longUrlSignature, SignatureAlgorithm signatureAlgorithm, + int signatureVersion, String oauthToken, boolean analytics) { this.cloudName = cloudName; @@ -98,6 +101,7 @@ private Configuration( this.forceVersion = forceVersion; this.longUrlSignature = longUrlSignature; this.signatureAlgorithm = signatureAlgorithm; + this.signatureVersion = signatureVersion; this.oauthToken = oauthToken; this.analytics = analytics; } @@ -140,6 +144,7 @@ public void update(Map config) { } this.longUrlSignature = ObjectUtils.asBoolean(config.get("long_url_signature"), DEFAULT_IS_LONG_SIGNATURE); this.signatureAlgorithm = SignatureAlgorithm.valueOf(ObjectUtils.asString(config.get(CONFIG_PROP_SIGNATURE_ALGORITHM), DEFAULT_SIGNATURE_ALGORITHM.name())); + this.signatureVersion = ObjectUtils.asInteger(config.get("signature_version"), DEFAULT_SIGNATURE_VERSION); this.oauthToken = (String) config.get("oauth_token"); } @@ -173,6 +178,7 @@ public Map asMap() { map.put("properties", new HashMap(properties)); map.put("long_url_signature", longUrlSignature); map.put(CONFIG_PROP_SIGNATURE_ALGORITHM, signatureAlgorithm.toString()); + map.put("signature_version", signatureVersion); map.put("oauth_token", oauthToken); map.put("analytics", analytics); return map; @@ -206,6 +212,7 @@ public Configuration(Configuration other) { this.properties.putAll(other.properties); this.longUrlSignature = other.longUrlSignature; this.signatureAlgorithm = other.signatureAlgorithm; + this.signatureVersion = other.signatureVersion; this.oauthToken = other.oauthToken; this.analytics = other.analytics; } @@ -320,6 +327,7 @@ public static class Builder { private boolean forceVersion = true; private boolean longUrlSignature = DEFAULT_IS_LONG_SIGNATURE; private SignatureAlgorithm signatureAlgorithm = DEFAULT_SIGNATURE_ALGORITHM; + private int signatureVersion = DEFAULT_SIGNATURE_VERSION; private String oauthToken = null; private boolean analytics; @@ -360,6 +368,7 @@ public Configuration build() { forceVersion, longUrlSignature, signatureAlgorithm, + signatureVersion, oauthToken, analytics); configuration.clientHints = clientHints; @@ -500,6 +509,11 @@ public Builder setSignatureAlgorithm(SignatureAlgorithm signatureAlgorithm) { return this; } + public Builder setSignatureVersion(int signatureVersion) { + this.signatureVersion = signatureVersion; + return this; + } + public Builder setOAuthToken(String oauthToken) { this.oauthToken = oauthToken; return this; @@ -535,6 +549,7 @@ public Builder from(Configuration other) { this.forceVersion = other.forceVersion; this.longUrlSignature = other.longUrlSignature; this.signatureAlgorithm = other.signatureAlgorithm; + this.signatureVersion = other.signatureVersion; this.oauthToken = other.oauthToken; this.analytics = other.analytics; return this; diff --git a/cloudinary-core/src/main/java/com/cloudinary/Util.java b/cloudinary-core/src/main/java/com/cloudinary/Util.java index f81da3cc..4f15c220 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Util.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Util.java @@ -366,8 +366,8 @@ public static byte[] getUTF8Bytes(String string) { * @param apiSecret secret value * @return hex-string representation of signature calculated based on provided parameters map and secret */ - public static String produceSignature(Map paramsToSign, String apiSecret) { - return produceSignature(paramsToSign, apiSecret, SignatureAlgorithm.SHA1); + public static String produceSignature(Map paramsToSign, String apiSecret, int signatureVersion) { + return produceSignature(paramsToSign, apiSecret, SignatureAlgorithm.SHA1, signatureVersion); } /** @@ -384,22 +384,42 @@ public static String produceSignature(Map paramsToSign, String a * @param signatureAlgorithm type of hashing algorithm to use for calculation of HMAC * @return hex-string representation of signature calculated based on provided parameters map and secret */ - public static String produceSignature(Map paramsToSign, String apiSecret, SignatureAlgorithm signatureAlgorithm) { - Collection params = new ArrayList(); - for (Map.Entry param : new TreeMap(paramsToSign).entrySet()) { - if (param.getValue() instanceof Collection) { - params.add(param.getKey() + "=" + StringUtils.join((Collection) param.getValue(), ",")); - } else if (param.getValue() instanceof Object[]) { - params.add(param.getKey() + "=" + StringUtils.join((Object[]) param.getValue(), ",")); - } else { - if (StringUtils.isNotBlank(param.getValue())) { - params.add(param.getKey() + "=" + param.getValue().toString()); - } + public static String produceSignature(Map paramsToSign, String apiSecret, SignatureAlgorithm signatureAlgorithm, int signatureVersion) { + Collection flattenedParams = flattenAndSanitizeParams(paramsToSign, signatureVersion); + String toSign = StringUtils.join(flattenedParams, "&") + apiSecret; + byte[] hash = Util.hash(toSign, signatureAlgorithm); + return StringUtils.encodeHexString(hash); + } + + private static Collection flattenAndSanitizeParams(Map paramsToSign, int signatureVersion) { + Collection params = new ArrayList<>(); + + for (Map.Entry entry : new TreeMap<>(paramsToSign).entrySet()) { + Object value = entry.getValue(); + String rawValue = null; + + if (value instanceof Collection) { + rawValue = StringUtils.join((Collection) value, ","); + } else if (value instanceof Object[]) { + rawValue = StringUtils.join((Object[]) value, ","); + } else if (value != null && StringUtils.isNotBlank(value.toString())) { + rawValue = value.toString(); + } + + if (rawValue != null) { + String sanitizedValue = (signatureVersion == 2) + ? escapeAmpersand(rawValue) + : rawValue; + + params.add(entry.getKey() + "=" + sanitizedValue); } } - String to_sign = StringUtils.join(params, "&"); - byte[] hash = Util.hash(to_sign + apiSecret, signatureAlgorithm); - return StringUtils.encodeHexString(hash); + + return params; + } + + private static String escapeAmpersand(String input) { + return input.replace("&", "%26"); } /** diff --git a/cloudinary-core/src/main/java/com/cloudinary/api/signing/ApiResponseSignatureVerifier.java b/cloudinary-core/src/main/java/com/cloudinary/api/signing/ApiResponseSignatureVerifier.java index 1dbae00d..f6d7da67 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/api/signing/ApiResponseSignatureVerifier.java +++ b/cloudinary-core/src/main/java/com/cloudinary/api/signing/ApiResponseSignatureVerifier.java @@ -60,6 +60,6 @@ public ApiResponseSignatureVerifier(String secretKey, SignatureAlgorithm signatu public boolean verifySignature(String publicId, String version, String signature) { return Util.produceSignature(ObjectUtils.asMap( "public_id", emptyIfNull(publicId), - "version", emptyIfNull(version)), secretKey, signatureAlgorithm).equals(signature); + "version", emptyIfNull(version)), secretKey, signatureAlgorithm, 1).equals(signature); } } diff --git a/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java b/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java index 18064976..c40a3ea2 100644 --- a/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java +++ b/cloudinary-core/src/test/java/com/cloudinary/test/CloudinaryTest.java @@ -1438,14 +1438,14 @@ public void testCloudinaryUrlEmptyScheme() { @Test public void testApiSignRequestSHA1() { cloudinary.config.signatureAlgorithm = SignatureAlgorithm.SHA1; - String signature = cloudinary.apiSignRequest(ObjectUtils.asMap("cloud_name", "dn6ot3ged", "timestamp", 1568810420, "username", "user@cloudinary.com"), "hdcixPpR2iKERPwqvH6sHdK9cyac"); + String signature = cloudinary.apiSignRequest(ObjectUtils.asMap("cloud_name", "dn6ot3ged", "timestamp", 1568810420, "username", "user@cloudinary.com"), "hdcixPpR2iKERPwqvH6sHdK9cyac", cloudinary.config.signatureVersion); assertEquals("14c00ba6d0dfdedbc86b316847d95b9e6cd46d94", signature); } @Test public void testApiSignRequestSHA256() { cloudinary.config.signatureAlgorithm = SignatureAlgorithm.SHA256; - String signature = cloudinary.apiSignRequest(ObjectUtils.asMap("cloud_name", "dn6ot3ged", "timestamp", 1568810420, "username", "user@cloudinary.com"), "hdcixPpR2iKERPwqvH6sHdK9cyac"); + String signature = cloudinary.apiSignRequest(ObjectUtils.asMap("cloud_name", "dn6ot3ged", "timestamp", 1568810420, "username", "user@cloudinary.com"), "hdcixPpR2iKERPwqvH6sHdK9cyac", cloudinary.config.signatureVersion); assertEquals("45ddaa4fa01f0c2826f32f669d2e4514faf275fe6df053f1a150e7beae58a3bd", signature); } diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java index 5c854d75..90e90fa7 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractApiTest.java @@ -1368,4 +1368,39 @@ public void testAllowDerivedNextCursor() throws Exception { cloudinary.uploader().destroy(publicId, Collections.singletonMap("invalidate", true)); } } + + @Test + public void testSignatureWithEscapingCharacters() { + String API_SIGN_REQUEST_CLOUD_NAME = "dn6ot3ged"; + String API_SIGN_REQUEST_TEST_SECRET = "hdcixPpR2iKERPwqvH6sHdK9cyac"; + + Map paramsWithAmpersand = new HashMap<>(); + paramsWithAmpersand.put("cloud_name", API_SIGN_REQUEST_CLOUD_NAME); + paramsWithAmpersand.put("timestamp", 1568810420); + paramsWithAmpersand.put("notification_url", "https://fake.com/callback?a=1&tags=hello,world"); + + String signatureWithAmpersand = Util.produceSignature(paramsWithAmpersand, API_SIGN_REQUEST_TEST_SECRET, cloudinary.config.signatureVersion); + + Map paramsSmuggled = new HashMap<>(); + paramsSmuggled.put("cloud_name", API_SIGN_REQUEST_CLOUD_NAME); + paramsSmuggled.put("timestamp", 1568810420); + paramsSmuggled.put("notification_url", "https://fake.com/callback?a=1"); + paramsSmuggled.put("tags", "hello,world"); + + String signatureSmuggled = Util.produceSignature(paramsSmuggled, API_SIGN_REQUEST_TEST_SECRET, cloudinary.config.signatureVersion); + + assertNotEquals(signatureWithAmpersand, signatureSmuggled, + "Signatures should be different to prevent parameter smuggling"); + + String expectedSignature = "4fdf465dd89451cc1ed8ec5b3e314e8a51695704"; + assertEquals(expectedSignature, signatureWithAmpersand); + + String expectedSmuggledSignature = "7b4e3a539ff1fa6e6700c41b3a2ee77586a025f9"; + assertEquals(expectedSmuggledSignature, signatureSmuggled); + + String versionOneSignature = Util.produceSignature(paramsSmuggled, API_SIGN_REQUEST_TEST_SECRET, 1); + + assertEquals(expectedSmuggledSignature, versionOneSignature); + + } } diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java index 5de797fa..794c926a 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractUploaderTest.java @@ -104,7 +104,7 @@ public void testUtf8Upload() throws IOException { Map to_sign = new HashMap(); to_sign.put("public_id", result.get("public_id")); to_sign.put("version", ObjectUtils.asString(result.get("version"))); - String expected_signature = cloudinary.apiSignRequest(to_sign, cloudinary.config.apiSecret); + String expected_signature = cloudinary.apiSignRequest(to_sign, cloudinary.config.apiSecret, cloudinary.config.signatureVersion); assertEquals(result.get("signature"), expected_signature); } @@ -131,7 +131,7 @@ public void testUpload() throws IOException { Map to_sign = new HashMap(); to_sign.put("public_id", result.get("public_id")); to_sign.put("version", ObjectUtils.asString(result.get("version"))); - String expected_signature = cloudinary.apiSignRequest(to_sign, cloudinary.config.apiSecret); + String expected_signature = cloudinary.apiSignRequest(to_sign, cloudinary.config.apiSecret, cloudinary.config.signatureVersion); assertEquals(result.get("signature"), expected_signature); } @@ -167,7 +167,7 @@ public void testUploadUrl() throws IOException { Map to_sign = new HashMap(); to_sign.put("public_id", result.get("public_id")); to_sign.put("version", ObjectUtils.asString(result.get("version"))); - String expected_signature = cloudinary.apiSignRequest(to_sign, cloudinary.config.apiSecret); + String expected_signature = cloudinary.apiSignRequest(to_sign, cloudinary.config.apiSecret, cloudinary.config.signatureVersion); assertEquals(result.get("signature"), expected_signature); } @@ -179,7 +179,7 @@ public void testUploadLargeUrl() throws IOException { Map to_sign = new HashMap(); to_sign.put("public_id", result.get("public_id")); to_sign.put("version", ObjectUtils.asString(result.get("version"))); - String expected_signature = cloudinary.apiSignRequest(to_sign, cloudinary.config.apiSecret); + String expected_signature = cloudinary.apiSignRequest(to_sign, cloudinary.config.apiSecret, cloudinary.config.signatureVersion); assertEquals(result.get("signature"), expected_signature); } @@ -191,7 +191,7 @@ public void testUploadDataUri() throws IOException { Map to_sign = new HashMap(); to_sign.put("public_id", result.get("public_id")); to_sign.put("version", ObjectUtils.asString(result.get("version"))); - String expected_signature = cloudinary.apiSignRequest(to_sign, cloudinary.config.apiSecret); + String expected_signature = cloudinary.apiSignRequest(to_sign, cloudinary.config.apiSecret, cloudinary.config.signatureVersion); assertEquals(result.get("signature"), expected_signature); } From 3a624a8b6d997b8c4f02a35338f928cf6cb8db6d Mon Sep 17 00:00:00 2001 From: adimiz1 Date: Wed, 18 Jun 2025 09:11:58 +0300 Subject: [PATCH 145/150] Version 2.3.0 --- CHANGELOG.md | 6 ++++++ README.md | 2 +- .../src/main/java/com/cloudinary/Cloudinary.java | 2 +- gradle.properties | 2 +- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ba03059e..f473f0ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +2.3.0 / 2025-06-18 +================== +* Fix API parameters signature +* Fix build single resource params +* Add skip backup parameter to delete folder api + 2.2.0 / 2025-02-02 ================== diff --git a/README.md b/README.md index f5659de0..1ed82876 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ The cloudinary_java library is available in [Maven Central](https://mvnrepositor com.cloudinary cloudinary-http45 - 2.2.0 + 2.3.0 ``` diff --git a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java index bbb07e36..869e20b6 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java @@ -32,7 +32,7 @@ public class Cloudinary { public final static String AKAMAI_SHARED_CDN = "res.cloudinary.com"; public final static String SHARED_CDN = AKAMAI_SHARED_CDN; - public final static String VERSION = "2.2.0"; + public final static String VERSION = "2.3.0"; static String USER_AGENT_PREFIX = "CloudinaryJava"; public final static String USER_AGENT_JAVA_VERSION = "(Java " + System.getProperty("java.version") + ")"; diff --git a/gradle.properties b/gradle.properties index aaea4f1d..0180f74f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,7 +13,7 @@ developerEmail=info@cloudinary.com # These two properties must use these exact names to be compatible with 'gradle install' plugin. group=com.cloudinary -version=2.2.0 +version=2.3.0 gnsp.disableApplyOnlyOnRootProjectEnforcement=true From 16e652092390e0c0ab618b32e6d21b58702ff8ee Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Sun, 13 Jul 2025 07:28:38 +0300 Subject: [PATCH 146/150] Add github actions script --- .github/workflows/build.yml | 50 +++++++++++++++++++++++++++++++++++++ .travis.yml | 36 -------------------------- 2 files changed, 50 insertions(+), 36 deletions(-) create mode 100644 .github/workflows/build.yml delete mode 100644 .travis.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 00000000..33920489 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,50 @@ +name: Java SDK Matrix CI + +on: + push: + branches-ignore: + - staging-test + pull_request: + +jobs: + build: + name: Test ${{ matrix.module }} on JDK ${{ matrix.java }} + runs-on: ubuntu-latest + + strategy: + matrix: + java: ['8'] + module: [ 'core', 'http5', 'taglib' ] + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up JDK ${{ matrix.java }} + uses: actions/setup-java@v4 + with: + distribution: 'adopt' + java-version: ${{ matrix.java }} + + - name: Clean Gradle plugin cache + run: | + rm -f $HOME/.gradle/caches/modules-2/modules-2.lock + rm -fr $HOME/.gradle/caches/*/plugin-resolution/ + + - name: Cache Gradle + uses: actions/cache@v4 + with: + path: | + ~/.gradle/caches + ~/.gradle/wrapper + key: ${{ runner.os }}-gradle-${{ matrix.java }}-${{ matrix.module }}-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} + restore-keys: | + ${{ runner.os }}-gradle- + + - name: Create test subaccount + run: ./gradlew createTestSubAccount -PmoduleName=${{ matrix.module }} + + - name: Load CLOUDINARY_URL and run ciTest + run: | + source tools/cloudinary_url.txt + ./gradlew -DCLOUDINARY_URL=$CLOUDINARY_URL ciTest -p cloudinary-${{ matrix.module }} -i \ No newline at end of file diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 8a1fec22..00000000 --- a/.travis.yml +++ /dev/null @@ -1,36 +0,0 @@ -language: java -dist: trusty - -before_cache: - - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock - - rm -fr $HOME/.gradle/caches/*/plugin-resolution/ -cache: - directories: - - $HOME/.gradle/caches/ - - $HOME/.gradle/wrapper/ - -jdk: - - oraclejdk8 - - oraclejdk9 - - oraclejdk11 - - openjdk8 - - openjdk10 - -env: - - MODULE=core - - MODULE=http5 - -branches: - except: - - staging-test - -before_script: ./gradlew createTestSubAccount -PmoduleName=${MODULE} - -# ciTest is configured to skip the various timeout tests that don't work in travis -script: source tools/cloudinary_url.txt && ./gradlew -DCLOUDINARY_URL=$CLOUDINARY_URL ciTest -p cloudinary-${MODULE} -i - - -notifications: - email: - recipients: - - sdk_developers@cloudinary.com From 98fc5187bbc021ceb78fb7a0abe2299e008cfcb2 Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Wed, 13 Aug 2025 11:39:46 +0300 Subject: [PATCH 147/150] Bump dependencies version --- cloudinary-http5/build.gradle | 2 +- cloudinary-taglib/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cloudinary-http5/build.gradle b/cloudinary-http5/build.gradle index b58b6c36..35c9857b 100644 --- a/cloudinary-http5/build.gradle +++ b/cloudinary-http5/build.gradle @@ -18,7 +18,7 @@ task ciTest( type: Test ) { dependencies { compile project(':cloudinary-core') - compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.1' + compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.18.0' api group: 'org.apache.httpcomponents.client5', name: 'httpclient5', version: '5.3.1' api group: 'org.apache.httpcomponents.core5', name: 'httpcore5', version: '5.2.5' testCompile project(':cloudinary-test-common') diff --git a/cloudinary-taglib/build.gradle b/cloudinary-taglib/build.gradle index 16b200f3..657c5bd8 100644 --- a/cloudinary-taglib/build.gradle +++ b/cloudinary-taglib/build.gradle @@ -11,7 +11,7 @@ task ciTest( type: Test ) dependencies { compile project(':cloudinary-core') - compile group: 'org.apache.commons', name: 'commons-lang3', version:'3.1' + compile group: 'org.apache.commons', name: 'commons-lang3', version:'3.18.0' testCompile group: 'org.hamcrest', name: 'java-hamcrest', version:'2.0.0.0' testCompile group: 'pl.pragmatists', name: 'JUnitParams', version:'1.0.5' testCompile group: 'junit', name: 'junit', version:'4.12' From 4d2e62b2f0886e3f6a7f499ed1996f1bb63acadd Mon Sep 17 00:00:00 2001 From: adimiz1 Date: Wed, 13 Aug 2025 11:44:14 +0300 Subject: [PATCH 148/150] Version 2.3.1 --- CHANGELOG.md | 5 +++++ README.md | 5 +---- cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java | 2 +- gradle.properties | 2 +- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f473f0ba..6cb9303b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +2.3.1 / 2025-08-13 +================== + +* Bump dependencies version + 2.3.0 / 2025-06-18 ================== * Fix API parameters signature diff --git a/README.md b/README.md index 1ed82876..1b28b43b 100644 --- a/README.md +++ b/README.md @@ -39,13 +39,10 @@ The cloudinary_java library is available in [Maven Central](https://mvnrepositor com.cloudinary cloudinary-http45 - 2.3.0 + 2.3.1 ``` -Alternatively, download cloudinary_java from [here](https://repo1.maven.org/maven2/com/cloudinary/cloudinary-core/1.30.0/cloudinary-core-1.30.0.jar) and [here](https://repo1.maven.org/maven2/com/cloudinary/cloudinary-http44/1.30.0/cloudinary-http44-1.30.0.jar) -and see [build.gradle](https://github.com/cloudinary/cloudinary_java/blob/master/cloudinary-http44/build.gradle) for library dependencies. - ## Usage ### Setup diff --git a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java index 869e20b6..1e69c4fe 100644 --- a/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java +++ b/cloudinary-core/src/main/java/com/cloudinary/Cloudinary.java @@ -32,7 +32,7 @@ public class Cloudinary { public final static String AKAMAI_SHARED_CDN = "res.cloudinary.com"; public final static String SHARED_CDN = AKAMAI_SHARED_CDN; - public final static String VERSION = "2.3.0"; + public final static String VERSION = "2.3.1"; static String USER_AGENT_PREFIX = "CloudinaryJava"; public final static String USER_AGENT_JAVA_VERSION = "(Java " + System.getProperty("java.version") + ")"; diff --git a/gradle.properties b/gradle.properties index 0180f74f..ac013e33 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,7 +13,7 @@ developerEmail=info@cloudinary.com # These two properties must use these exact names to be compatible with 'gradle install' plugin. group=com.cloudinary -version=2.3.0 +version=2.3.1 gnsp.disableApplyOnlyOnRootProjectEnforcement=true From d836d6ee9a5f1507b23697c459a37da409eaef89 Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Tue, 26 Aug 2025 08:47:47 +0300 Subject: [PATCH 149/150] Fix publish scripts --- MAVEN_CENTRAL_PUBLISHING_GUIDE.md | 437 ++++++++++++++++++++++++++++ build.gradle | 18 +- cloudinary-core/build.gradle | 89 +----- cloudinary-http5/build.gradle | 89 +----- cloudinary-taglib/build.gradle | 89 +----- cloudinary-test-common/build.gradle | 89 +----- gradle.properties | 6 +- publish.gradle | 73 +++++ 8 files changed, 524 insertions(+), 366 deletions(-) create mode 100644 MAVEN_CENTRAL_PUBLISHING_GUIDE.md create mode 100644 publish.gradle diff --git a/MAVEN_CENTRAL_PUBLISHING_GUIDE.md b/MAVEN_CENTRAL_PUBLISHING_GUIDE.md new file mode 100644 index 00000000..6fb96006 --- /dev/null +++ b/MAVEN_CENTRAL_PUBLISHING_GUIDE.md @@ -0,0 +1,437 @@ +# Maven Central Publishing Guide - Cloudinary Java SDK + +This guide documents the complete process for publishing the Cloudinary Java SDK to Maven Central using the new Central Portal (central.sonatype.com), replacing the deprecated OSSRH system. + +## 🎯 **Overview** + +- **Old System:** `oss.sonatype.org` (dead, returns 401 errors) +- **New System:** `central.sonatype.com` with manual bundle upload +- **Method:** Manual bundle creation and upload (not automated plugin publishing) +- **Requirements:** Complete artifacts with checksums and GPG signatures +- **Current Version:** 2.3.1 β†’ Next version (e.g., 2.3.2) + +## πŸ“‹ **Prerequisites** + +1. **Credentials:** + - `centralUsername` and `centralPassword` for central.sonatype.com + - Legacy `ossrhToken` and `ossrhTokenPassword` (if available) + +2. **GPG Setup:** + - GPG key imported: `6B42474E50D0D89A01B40AC225FE63F85DCB788F` + - Private key available in repository: `private-key.asc` + - Password: `nwov0aaStnO4` + +3. **Java Version:** + - **Java 8+** (current project targets Java 8) + - Verify with: `java -version` + +## πŸ”§ **Configuration Changes Required** + +### 1. Update Root `build.gradle` + +```gradle +plugins { + id 'maven-publish' + // Remove the old nexus plugin: id 'io.github.gradle-nexus.publish-plugin' version '1.0.0' +} + +allprojects { + repositories { + mavenCentral() + } + project.ext.set("publishGroupId", group) +} + +// Remove the old nexusPublishing block - we'll create bundles manually for Central Portal + +tasks.create('createTestSubAccount') { + doFirst { + println("Task createTestSubAccount called with module $moduleName") + def cloudinaryUrl = "" + + // core does not use test clouds, skip (keep empty file for a more readable generic travis test script) + if (moduleName != "core") { + println "Creating test cloud..." + def baseUrl = new URL('https://sub-account-testing.cloudinary.com/create_sub_account') + def connection = baseUrl.openConnection() + connection.with { + doOutput = true + requestMethod = 'POST' + def json = new JsonSlurper().parseText(content.text) + def cloud = json["payload"]["cloudName"] + def key = json["payload"]["cloudApiKey"] + def secret = json["payload"]["cloudApiSecret"] + cloudinaryUrl = "CLOUDINARY_URL=cloudinary://$key:$secret@$cloud" + } + } + + def dir = new File("${projectDir.path}${File.separator}tools") + dir.mkdir() + def file = new File(dir, "cloudinary_url.txt") + file.createNewFile() + file.text = cloudinaryUrl + + println("Test sub-account created successfully!") + } +} +``` + +### 2. Create New `publish.gradle` for Modules + +```gradle +apply plugin: 'maven-publish' +apply plugin: 'signing' + +// Simple module-level publishing for manual upload to Central Portal +if (hasProperty("ossrhTokenPassword") || hasProperty("centralPassword")) { + + publishing { + publications { + mavenJava(MavenPublication) { + // Set coordinates from gradle.properties + groupId = project.ext.publishGroupId + artifactId = project.name + version = project.version + + // Include JAR artifacts and components for Java + from components.java + artifact sourcesJar + artifact javadocJar + + pom { + name = getModuleName(project.name) + packaging = 'jar' + description = publishDescription + url = githubUrl + + licenses { + license { + name = licenseName + url = licenseUrl + } + } + + developers { + developer { + id = developerId + name = developerName + email = developerEmail + } + } + + scm { + connection = scmConnection + developerConnection = scmDeveloperConnection + url = scmUrl + } + } + } + } + } + + signing { + // Configure GPG signing + useGpgCmd() + sign publishing.publications.mavenJava + } +} + +// Helper function to get proper module names +def getModuleName(artifactId) { + switch(artifactId) { + case 'cloudinary-core': + return 'Cloudinary Core Library' + case 'cloudinary-http5': + return 'Cloudinary Apache HTTP 5 Library' + case 'cloudinary-taglib': + return 'Cloudinary Taglib Library' + case 'cloudinary-test-common': + return 'Cloudinary Test Common Library' + default: + return 'Cloudinary Java Library' + } +} +``` + +### 3. Update Module `build.gradle` Files + +For each module (cloudinary-core, cloudinary-http5, cloudinary-taglib, cloudinary-test-common), replace the publishing section: + +```gradle +plugins { + id 'java-library' + // Remove: id 'signing' + // Remove: id 'maven-publish' + // Remove: id 'io.codearte.nexus-staging' version '0.21.1' +} + +apply from: "../java_shared.gradle" +apply from: "../publish.gradle" // Apply our new simplified publishing + +// Remove the entire old publishing block with nexusStaging +// The new publish.gradle handles everything +``` + +### 4. Update `gradle.properties` + +```properties +# Update URLs to point to new system (for documentation) +publishRepo=https://central.sonatype.com/ +snapshotRepo=https://central.sonatype.com/ +publishDescription=Cloudinary is a cloud service that offers a solution to a web application's entire image management pipeline. Upload images to the cloud. Automatically perform smart image resizing, cropping and conversion without installing any complex software. Integrate Facebook or Twitter profile image extraction in a snap, in any dimension and style to match your website's graphics requirements. Images are seamlessly delivered through a fast CDN, and much much more. This Java library allows to easily integrate with Cloudinary in Java applications. +githubUrl=http://github.com/cloudinary/cloudinary_java +scmConnection=scm:git:git://github.com/cloudinary/cloudinary_java.git +scmDeveloperConnection=scm:git:git@github.com:cloudinary/cloudinary_java.git +scmUrl=http://github.com/cloudinary/cloudinary_java +licenseName=MIT +licenseUrl=http://opensource.org/licenses/MIT +developerId=cloudinary +developerName=Cloudinary +developerEmail=info@cloudinary.com + +# Update version for next release +group=com.cloudinary +version=2.3.2 + +gnsp.disableApplyOnlyOnRootProjectEnforcement=true + +# see https://github.com/gradle/gradle/issues/11308 +systemProp.org.gradle.internal.publish.checksums.insecure=true +``` + +## πŸš€ **Step-by-Step Publishing Process** + +### Step 1: Environment Setup + +```bash +# Navigate to project +cd /Users/adimizrahi/Development/Java/cloudinary_java + +# Verify Java version (should be Java 8+) +java -version +javac -version + +# Set GPG environment for batch signing +export GPG_TTY=$(tty) +``` + +### Step 2: Clean and Build All Artifacts + +```bash +# Clean previous builds and generate all artifacts +./gradlew clean publishToMavenLocal +``` + +**Expected Output:** +- JAR files for each module (cloudinary-core, cloudinary-http5, cloudinary-taglib, cloudinary-test-common) +- Sources JARs (`-sources.jar`) +- Javadoc JARs (`-javadoc.jar`) +- POM files with correct XML structure +- All artifacts signed with GPG (`.asc` files) + +### Step 3: Verify Artifacts Generated + +```bash +# Check that all 4 modules have complete artifacts (should be 7 files each) +for module in ~/.m2/repository/com/cloudinary/cloudinary-*; do + if [[ -d "$module" ]]; then + echo "--- $(basename $module) ---" + ls -1 $module/2.3.2/ 2>/dev/null | grep -E "\.(jar|pom|asc)$" | wc -l + fi +done +``` + +**Expected:** Each module should show `7` files: +- `cloudinary-module-2.3.2.jar` + `.asc` +- `cloudinary-module-2.3.2-sources.jar` + `.asc` +- `cloudinary-module-2.3.2-javadoc.jar` + `.asc` +- `cloudinary-module-2.3.2.pom` + `.asc` + +### Step 4: Verify POM Files Are Valid + +```bash +# Check that POM files have proper metadata +for pom in ~/.m2/repository/com/cloudinary/cloudinary-*/2.3.2/*.pom; do + if [[ -f "$pom" ]]; then + echo "--- $(basename $pom) ---" + echo "Name tags: $(grep -c "" "$pom")" + echo "Description: $(grep -c "" "$pom")" + echo "License: $(grep -c "" "$pom")" + echo "Developer: $(grep -c "" "$pom")" + echo "SCM: $(grep -c "" "$pom")" + fi +done +``` + +**Expected:** Each POM should have all required metadata elements. + +### Step 5: Generate Additional Checksums + +```bash +cd ~/.m2/repository + +# Generate MD5 and SHA1 checksums for all artifacts (Central Portal requires these) +find com/cloudinary/cloudinary-* -name "*.jar" -o -name "*.pom" | while read file; do + if [[ -f "$file" ]]; then + echo "Processing $file" + md5sum "$file" | awk '{print $1}' > "$file.md5" + sha1sum "$file" | awk '{print $1}' > "$file.sha1" + fi +done +``` + +### Step 6: Verify Complete File Set + +```bash +cd ~/.m2/repository + +echo "=== FINAL FILE COUNT CHECK ===" +echo "JAR/POM files:" && find com/cloudinary/cloudinary-* -name "*.jar" -o -name "*.pom" | wc -l +echo "GPG signatures:" && find com/cloudinary/cloudinary-* -name "*.asc" | wc -l +echo "MD5 checksums:" && find com/cloudinary/cloudinary-* -name "*.md5" | wc -l +echo "SHA1 checksums:" && find com/cloudinary/cloudinary-* -name "*.sha1" | wc -l +``` + +**Expected File Count:** +- 4 modules Γ— 4 artifacts each = **16 original files** +- **16 GPG signatures** (`.asc`) +- **16 MD5 checksums** (`.md5`) +- **16 SHA1 checksums** (`.sha1`) +- **Total: 64 files** + +### Step 7: Create Final Bundle + +```bash +cd ~/.m2/repository + +# Create the complete bundle for Central Portal upload +BUNDLE_NAME="cloudinary-java-$(grep '^version=' ~/Development/Java/cloudinary_java/gradle.properties | cut -d'=' -f2)-bundle-COMPLETE.tar.gz" + +tar -czf ~/"$BUNDLE_NAME" \ +$(find com/cloudinary/cloudinary-* \ + -name "*.pom" -o -name "*.jar" \ + -o -name "*.md5" -o -name "*.sha1" -o -name "*.asc" | \ + grep -v maven-metadata | sort) +``` + +### Step 8: Verify Final Bundle + +```bash +cd ~/ + +# Check bundle size and contents +ls -lh cloudinary-java-*-bundle-COMPLETE.tar.gz +echo "--- File count ---" +tar -tzf cloudinary-java-*-bundle-COMPLETE.tar.gz | wc -l +echo "--- Sample contents ---" +tar -tzf cloudinary-java-*-bundle-COMPLETE.tar.gz | head -16 +echo "--- Module breakdown ---" +tar -tzf cloudinary-java-*-bundle-COMPLETE.tar.gz | grep -E "(core|http5|taglib|test-common)" | cut -d'/' -f3 | sort | uniq -c +``` + +**Expected:** +- **Size:** ~1-2MB (smaller than Android due to fewer dependencies) +- **Files:** 64 total +- **Modules:** 4 modules with 16 files each +- **Contents:** Each module should have JARs, POMs, and all checksums/signatures + +## πŸ“€ **Upload to Central Portal** + +### Manual Upload Process + +1. **Login:** Go to https://central.sonatype.com/ +2. **Credentials:** Use `centralUsername` and `centralPassword` +3. **Upload:** Navigate to "Upload Component" or "Publish" +4. **Bundle:** Select the `.tar.gz` file created in Step 7 +5. **Publishing Type:** Choose "USER_MANAGED" +6. **Publication Name:** "Cloudinary Java SDK v{version}" + +### Expected Validation + +The Central Portal will validate: +- βœ… **POM structure** (proper XML with required metadata) +- βœ… **Artifact integrity** (MD5/SHA1 checksums match) +- βœ… **Signatures** (GPG signatures valid) +- βœ… **Completeness** (all required files present) +- βœ… **Java compatibility** (JAR files are valid) + +## πŸ›  **Troubleshooting** + +### Common Issues & Solutions + +1. **GPG Signing Issues:** + - **Cause:** TTY or batch mode problems + - **Solution:** `export GPG_TTY=$(tty)` and use `--batch --yes` flags + - **Alternative:** Use `signing { useGpgCmd() }` in Gradle + +2. **Missing Dependencies in POM:** + - **Cause:** Gradle not including transitive dependencies + - **Solution:** Verify `from components.java` includes dependencies + - **Check:** Examine generated POM files for `` section + +3. **Version Conflicts:** + - **Cause:** Old artifacts in local repository + - **Solution:** `./gradlew clean` and delete `~/.m2/repository/com/cloudinary/` + +4. **Module Configuration Issues:** + - **Cause:** Inconsistent `build.gradle` files between modules + - **Solution:** Ensure all modules apply `publish.gradle` consistently + +5. **Bundle Upload Failures:** + - **Cause:** Missing or corrupted files in bundle + - **Solution:** Verify all 64 files present and re-create bundle + +## πŸ“‹ **Module-Specific Information** + +### Cloudinary Core (`cloudinary-core`) +- **Artifact ID:** `cloudinary-core` +- **Description:** Core Cloudinary functionality +- **Dependencies:** Minimal (mostly standard Java libraries) + +### Cloudinary HTTP5 (`cloudinary-http5`) +- **Artifact ID:** `cloudinary-http5` +- **Description:** Apache HTTP Client 5 implementation +- **Dependencies:** `cloudinary-core`, Apache HTTP Components + +### Cloudinary Taglib (`cloudinary-taglib`) +- **Artifact ID:** `cloudinary-taglib` +- **Description:** JSP Taglib for Cloudinary +- **Dependencies:** `cloudinary-core`, Servlet API + +### Cloudinary Test Common (`cloudinary-test-common`) +- **Artifact ID:** `cloudinary-test-common` +- **Description:** Shared test utilities +- **Dependencies:** `cloudinary-core`, JUnit, test frameworks + +## πŸ“ **Version Update Checklist** + +For publishing a new version: + +- [ ] Update `version` in `gradle.properties` +- [ ] Update this guide with new version number +- [ ] Run complete publishing process (Steps 1-8) +- [ ] Verify all 64 files in final bundle (4 modules Γ— 16 files) +- [ ] Upload to Central Portal +- [ ] Verify publication appears on Maven Central +- [ ] Update GitHub releases and tags +- [ ] Test artifacts can be consumed by dependent projects + +## πŸ”— **References** + +- **Central Portal:** https://central.sonatype.com/ +- **Migration Guide:** https://central.sonatype.org/publish/publish-guide/ +- **Gradle Publishing:** https://docs.gradle.org/current/userguide/publishing_maven.html + +--- + +**Last Updated:** [Current Date] +**Tested Version:** 2.3.2 +**Success Rate:** βœ… To be tested with this process + +## 🚨 **Key Differences from Android SDK** + +1. **No AAR files** - Uses JAR files instead +2. **Java components** - Uses `components.java` instead of `components.release` +3. **Simpler setup** - No Android-specific build tools required +4. **Standard Maven structure** - Follows typical Java library patterns +5. **Fewer files per module** - 16 files per module vs 24 for Android modules diff --git a/build.gradle b/build.gradle index 5b9d6f04..ae30f0db 100644 --- a/build.gradle +++ b/build.gradle @@ -1,30 +1,18 @@ import groovy.json.JsonSlurper plugins { - id 'io.github.gradle-nexus.publish-plugin' version '1.0.0' + id 'maven-publish' + // Removed old nexus plugin - we'll create bundles manually for Central Portal } allprojects { - repositories { mavenCentral() } - project.ext.set("publishGroupId", group) } -nexusPublishing { - transitionCheckOptions { - maxRetries.set(150) - delayBetween.set(Duration.ofSeconds(5)) - } - repositories { - sonatype { - username = project.hasProperty("ossrhToken") ? project.ext["ossrhToken"] : "" - password = project.hasProperty("ossrhTokenPassword") ? project.ext["ossrhTokenPassword"] : "" - } - } -} +// Removed nexusPublishing block - we'll create bundles manually for Central Portal upload tasks.create('createTestSubAccount') { doFirst { diff --git a/cloudinary-core/build.gradle b/cloudinary-core/build.gradle index 01ac348b..67379690 100644 --- a/cloudinary-core/build.gradle +++ b/cloudinary-core/build.gradle @@ -1,8 +1,5 @@ plugins { id 'java-library' - id 'signing' - id 'maven-publish' - id 'io.codearte.nexus-staging' version '0.21.1' } task ciTest( type: Test ) @@ -14,88 +11,6 @@ dependencies { } apply from: "../java_shared.gradle" +apply from: "../publish.gradle" -if (hasProperty("ossrhPassword")) { - signing { - sign configurations.archives - } - - - nexusStaging { - packageGroup = group - username = project.hasProperty("ossrhToken") ? project.ext["ossrhToken"] : "" - password = project.hasProperty("ossrhTokenPassword") ? project.ext["ossrhTokenPassword"] : "" - } - - publishing { - publications { - mavenJava(MavenPublication) { - from components.java - artifact sourcesJar - artifact javadocJar - pom { - name = 'Cloudinary Core Library' - packaging = 'jar' - groupId = publishGroupId - artifactId = 'cloudinary-core' - description = publishDescription - url = githubUrl - licenses { - license { - name = licenseName - url = licenseUrl - } - } - - developers { - developer { - id = developerId - name = developerName - email = developerEmail - } - } - scm { - connection = scmConnection - developerConnection = scmDeveloperConnection - url = scmUrl - } - } - - pom.withXml { - def pomFile = file("${project.buildDir}/generated-pom.xml") - writeTo(pomFile) - def pomAscFile = signing.sign(pomFile).signatureFiles[0] - artifact(pomAscFile) { - classifier = null - extension = 'pom.asc' - } - } - - // create the signed artifacts - project.tasks.signArchives.signatureFiles.each { - artifact(it) { - def matcher = it.file =~ /-(sources|javadoc)\.jar\.asc$/ - if (matcher.find()) { - classifier = matcher.group(1) - } else { - classifier = null - } - extension = 'jar.asc' - } - } - } - } - - model { - tasks.generatePomFileForMavenJavaPublication { - destination = file("$buildDir/generated-pom.xml") - } - tasks.publishMavenJavaPublicationToMavenLocal { - dependsOn project.tasks.signArchives - } - tasks.publishMavenJavaPublicationToSonatypeRepository { - dependsOn project.tasks.signArchives - } - } - } -} \ No newline at end of file +// Publishing configuration moved to ../publish.gradle \ No newline at end of file diff --git a/cloudinary-http5/build.gradle b/cloudinary-http5/build.gradle index 35c9857b..07f6c8a6 100644 --- a/cloudinary-http5/build.gradle +++ b/cloudinary-http5/build.gradle @@ -1,11 +1,9 @@ plugins { id 'java-library' - id 'signing' - id 'maven-publish' - id 'io.codearte.nexus-staging' version '0.21.1' } apply from: "../java_shared.gradle" +apply from: "../publish.gradle" task ciTest( type: Test ) { useJUnit { @@ -27,87 +25,4 @@ dependencies { testCompile group: 'junit', name: 'junit', version: '4.12' } -if (hasProperty("ossrhPassword")) { - - signing { - sign configurations.archives - } - - nexusStaging { - packageGroup = group - username = project.hasProperty("ossrhToken") ? project.ext["ossrhToken"] : "" - password = project.hasProperty("ossrhTokenPassword") ? project.ext["ossrhTokenPassword"] : "" - } - - publishing { - publications { - mavenJava(MavenPublication) { - from components.java - artifact sourcesJar - artifact javadocJar - pom { - name = 'Cloudinary Apache HTTP 5 Library' - packaging = 'jar' - groupId = publishGroupId - artifactId = 'cloudinary-http5' - description = publishDescription - url = githubUrl - licenses { - license { - name = licenseName - url = licenseUrl - } - } - - developers { - developer { - id = developerId - name = developerName - email = developerEmail - } - } - scm { - connection = scmConnection - developerConnection = scmDeveloperConnection - url = scmUrl - } - } - - pom.withXml { - def pomFile = file("${project.buildDir}/generated-pom.xml") - writeTo(pomFile) - def pomAscFile = signing.sign(pomFile).signatureFiles[0] - artifact(pomAscFile) { - classifier = null - extension = 'pom.asc' - } - } - - // create the signed artifacts - project.tasks.signArchives.signatureFiles.each { - artifact(it) { - def matcher = it.file =~ /-(sources|javadoc)\.jar\.asc$/ - if (matcher.find()) { - classifier = matcher.group(1) - } else { - classifier = null - } - extension = 'jar.asc' - } - } - } - } - - model { - tasks.generatePomFileForMavenJavaPublication { - destination = file("$buildDir/generated-pom.xml") - } - tasks.publishMavenJavaPublicationToMavenLocal { - dependsOn project.tasks.signArchives - } - tasks.publishMavenJavaPublicationToSonatypeRepository { - dependsOn project.tasks.signArchives - } - } - } -} +// Publishing configuration moved to ../publish.gradle diff --git a/cloudinary-taglib/build.gradle b/cloudinary-taglib/build.gradle index 657c5bd8..ef8824af 100644 --- a/cloudinary-taglib/build.gradle +++ b/cloudinary-taglib/build.gradle @@ -1,11 +1,9 @@ plugins { id 'java-library' - id 'signing' - id 'maven-publish' - id 'io.codearte.nexus-staging' version '0.21.1' } apply from: "../java_shared.gradle" +apply from: "../publish.gradle" task ciTest( type: Test ) @@ -22,87 +20,4 @@ dependencies { } } -if (hasProperty("ossrhPassword")) { - - signing { - sign configurations.archives - } - - nexusStaging { - packageGroup = group - username = project.hasProperty("ossrhToken") ? project.ext["ossrhToken"] : "" - password = project.hasProperty("ossrhTokenPassword") ? project.ext["ossrhTokenPassword"] : "" - } - - publishing { - publications { - mavenJava(MavenPublication) { - from components.java - artifact sourcesJar - artifact javadocJar - pom { - name = 'Cloudinary Taglib Library' - packaging = 'jar' - groupId = publishGroupId - artifactId = 'cloudinary-taglib' - description = publishDescription - url = githubUrl - licenses { - license { - name = licenseName - url = licenseUrl - } - } - - developers { - developer { - id = developerId - name = developerName - email = developerEmail - } - } - scm { - connection = scmConnection - developerConnection = scmDeveloperConnection - url = scmUrl - } - } - - pom.withXml { - def pomFile = file("${project.buildDir}/generated-pom.xml") - writeTo(pomFile) - def pomAscFile = signing.sign(pomFile).signatureFiles[0] - artifact(pomAscFile) { - classifier = null - extension = 'pom.asc' - } - } - - // create the signed artifacts - project.tasks.signArchives.signatureFiles.each { - artifact(it) { - def matcher = it.file =~ /-(sources|javadoc)\.jar\.asc$/ - if (matcher.find()) { - classifier = matcher.group(1) - } else { - classifier = null - } - extension = 'jar.asc' - } - } - } - } - - model { - tasks.generatePomFileForMavenJavaPublication { - destination = file("$buildDir/generated-pom.xml") - } - tasks.publishMavenJavaPublicationToMavenLocal { - dependsOn project.tasks.signArchives - } - tasks.publishMavenJavaPublicationToSonatypeRepository { - dependsOn project.tasks.signArchives - } - } - } -} \ No newline at end of file +// Publishing configuration moved to ../publish.gradle \ No newline at end of file diff --git a/cloudinary-test-common/build.gradle b/cloudinary-test-common/build.gradle index daa5ce83..e387870b 100644 --- a/cloudinary-test-common/build.gradle +++ b/cloudinary-test-common/build.gradle @@ -1,11 +1,9 @@ plugins { id 'java-library' - id 'signing' - id 'maven-publish' - id 'io.codearte.nexus-staging' version '0.21.1' } apply from: "../java_shared.gradle" +apply from: "../publish.gradle" task ciTest( type: Test ) @@ -16,87 +14,4 @@ dependencies { testCompile group: 'pl.pragmatists', name: 'JUnitParams', version: '1.0.5' } -if (hasProperty("ossrhPassword")) { - - signing { - sign configurations.archives - } - - nexusStaging { - packageGroup = group - username = project.hasProperty("ossrhToken") ? project.ext["ossrhToken"] : "" - password = project.hasProperty("ossrhTokenPassword") ? project.ext["ossrhTokenPassword"] : "" - } - - publishing { - publications { - mavenJava(MavenPublication) { - from components.java - artifact sourcesJar - artifact javadocJar - pom { - name = 'Cloudinary Test Common' - packaging = 'jar' - groupId = publishGroupId - artifactId = 'cloudinary-test-common' - description = publishDescription - url = githubUrl - licenses { - license { - name = licenseName - url = licenseUrl - } - } - - developers { - developer { - id = developerId - name = developerName - email = developerEmail - } - } - scm { - connection = scmConnection - developerConnection = scmDeveloperConnection - url = scmUrl - } - } - - pom.withXml { - def pomFile = file("${project.buildDir}/generated-pom.xml") - writeTo(pomFile) - def pomAscFile = signing.sign(pomFile).signatureFiles[0] - artifact(pomAscFile) { - classifier = null - extension = 'pom.asc' - } - } - - // create the signed artifacts - project.tasks.signArchives.signatureFiles.each { - artifact(it) { - def matcher = it.file =~ /-(sources|javadoc)\.jar\.asc$/ - if (matcher.find()) { - classifier = matcher.group(1) - } else { - classifier = null - } - extension = 'jar.asc' - } - } - } - } - - model { - tasks.generatePomFileForMavenJavaPublication { - destination = file("$buildDir/generated-pom.xml") - } - tasks.publishMavenJavaPublicationToMavenLocal { - dependsOn project.tasks.signArchives - } - tasks.publishMavenJavaPublicationToSonatypeRepository { - dependsOn project.tasks.signArchives - } - } - } -} \ No newline at end of file +// Publishing configuration moved to ../publish.gradle \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index ac013e33..2fc928d3 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ -publishRepo=https://oss.sonatype.org/service/local/staging/deploy/maven2/ -snapshotRepo=https://oss.sonatype.org/content/repositories/snapshots/ +publishRepo=https://central.sonatype.com/ +snapshotRepo=https://central.sonatype.com/ publishDescription=Cloudinary is a cloud service that offers a solution to a web application's entire image management pipeline. Upload images to the cloud. Automatically perform smart image resizing, cropping and conversion without installing any complex software. Integrate Facebook or Twitter profile image extraction in a snap, in any dimension and style to match your website’s graphics requirements. Images are seamlessly delivered through a fast CDN, and much much more. This Java library allows to easily integrate with Cloudinary in Java applications. githubUrl=http://github.com/cloudinary/cloudinary_java scmConnection=scm:git:git://github.com/cloudinary/cloudinary_java.git @@ -13,7 +13,7 @@ developerEmail=info@cloudinary.com # These two properties must use these exact names to be compatible with 'gradle install' plugin. group=com.cloudinary -version=2.3.1 +version=2.3.2 gnsp.disableApplyOnlyOnRootProjectEnforcement=true diff --git a/publish.gradle b/publish.gradle new file mode 100644 index 00000000..80eb3ea9 --- /dev/null +++ b/publish.gradle @@ -0,0 +1,73 @@ +apply plugin: 'maven-publish' +apply plugin: 'signing' + +// Simple module-level publishing for manual upload to Central Portal +if (hasProperty("ossrhTokenPassword") || hasProperty("centralPassword")) { + + publishing { + publications { + mavenJava(MavenPublication) { + // Set coordinates from gradle.properties + groupId = project.ext.publishGroupId + artifactId = project.name + version = project.version + + // Include JAR artifacts and components for Java + from components.java + artifact sourcesJar + artifact javadocJar + + pom { + name = getModuleName(project.name) + packaging = 'jar' + description = publishDescription + url = githubUrl + + licenses { + license { + name = licenseName + url = licenseUrl + } + } + + developers { + developer { + id = developerId + name = developerName + email = developerEmail + } + } + + scm { + connection = scmConnection + developerConnection = scmDeveloperConnection + url = scmUrl + } + } + } + } + } + + // Signing temporarily disabled - we'll add GPG signatures manually using command line + // signing { + // required { project.hasProperty("centralPassword") } + // useGpgCmd() + // sign publishing.publications.mavenJava + // } +} + +// Helper function to get proper module names +def getModuleName(artifactId) { + switch(artifactId) { + case 'cloudinary-core': + return 'Cloudinary Core Library' + case 'cloudinary-http5': + return 'Cloudinary Apache HTTP 5 Library' + case 'cloudinary-taglib': + return 'Cloudinary Taglib Library' + case 'cloudinary-test-common': + return 'Cloudinary Test Common Library' + default: + return 'Cloudinary Java Library' + } +} \ No newline at end of file From e682979b3dae98ee961b8ca197b054fb5d77cf7d Mon Sep 17 00:00:00 2001 From: adimiz1 <95848801+adimiz1@users.noreply.github.com> Date: Sun, 31 May 2026 12:46:04 +0300 Subject: [PATCH 150/150] Bump httpcore5 5.2.5 -> 5.3.5 --- cloudinary-http5/build.gradle | 2 +- .../com/cloudinary/test/AbstractStructuredMetadataTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cloudinary-http5/build.gradle b/cloudinary-http5/build.gradle index 07f6c8a6..ceeab84e 100644 --- a/cloudinary-http5/build.gradle +++ b/cloudinary-http5/build.gradle @@ -18,7 +18,7 @@ dependencies { compile project(':cloudinary-core') compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.18.0' api group: 'org.apache.httpcomponents.client5', name: 'httpclient5', version: '5.3.1' - api group: 'org.apache.httpcomponents.core5', name: 'httpcore5', version: '5.2.5' + api group: 'org.apache.httpcomponents.core5', name: 'httpcore5', version: '5.3.5' testCompile project(':cloudinary-test-common') testCompile group: 'org.hamcrest', name: 'java-hamcrest', version: '2.0.0.0' testCompile group: 'pl.pragmatists', name: 'JUnitParams', version: '1.0.5' diff --git a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractStructuredMetadataTest.java b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractStructuredMetadataTest.java index b1137fb4..4fe51219 100644 --- a/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractStructuredMetadataTest.java +++ b/cloudinary-test-common/src/main/java/com/cloudinary/test/AbstractStructuredMetadataTest.java @@ -84,7 +84,7 @@ public void testCreateSetMetadataWithAllowDynamicListValues() throws Exception { @Test public void testFieldRestrictions() throws Exception { - StringMetadataField stringField = newFieldInstance("testCreateMetadata_3", true); + StringMetadataField stringField = newFieldInstance("testCreateMetadata_3", false); stringField.setRestrictions(new Restrictions().setReadOnlyUI()); ApiResponse result = api.addMetadataField(stringField);