diff --git a/app/client/cypress/integration/Smoke_TestSuite/ServerSideTests/QueryPane/S3_spec.js b/app/client/cypress/integration/Smoke_TestSuite/ServerSideTests/QueryPane/S3_spec.js index 8c0a9de9ca..3690481daa 100644 --- a/app/client/cypress/integration/Smoke_TestSuite/ServerSideTests/QueryPane/S3_spec.js +++ b/app/client/cypress/integration/Smoke_TestSuite/ServerSideTests/QueryPane/S3_spec.js @@ -120,7 +120,7 @@ describe("Validate CRUD queries for Amazon S3 along with UI flow verifications", "File content is not base64 encoded.", ); }); - cy.validateNSelectDropdown("File Data Type", "Base64", "Text / Binary"); + cy.validateNSelectDropdown("File Data Type", "Base64", "Text"); cy.onlyQueryRun(); cy.wait("@postExecute").then(({ response }) => { @@ -249,7 +249,7 @@ describe("Validate CRUD queries for Amazon S3 along with UI flow verifications", cy.typeValueNValidate("AutoFile", "File Path"); //Commenting below since below dropdown is removed from Read - //cy.validateNSelectDropdown("File Data Type", "Base64", "Text / Binary"); + //cy.validateNSelectDropdown("File Data Type", "Base64", "Text"); cy.onlyQueryRun(); cy.wait("@postExecute").then(({ response }) => { @@ -343,7 +343,7 @@ describe("Validate CRUD queries for Amazon S3 along with UI flow verifications", ); cy.typeValueNValidate("assets-test.appsmith.com", "Bucket Name"); cy.typeValueNValidate("CRUDNewPageFile", "File Path"); - cy.validateNSelectDropdown("File Data Type", "Base64", "Text / Binary"); + cy.validateNSelectDropdown("File Data Type", "Base64", "Text"); cy.typeValueNValidate( '{"data": "Hi, this is Automation script adding file for S3 CRUD New Page validation!"}', "Content", diff --git a/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/helpers/PluginUtils.java b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/helpers/PluginUtils.java index 2533703e4f..95b87dbd86 100644 --- a/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/helpers/PluginUtils.java +++ b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/helpers/PluginUtils.java @@ -6,6 +6,7 @@ import com.appsmith.external.exceptions.pluginExceptions.AppsmithPluginException import com.appsmith.external.models.Condition; import com.appsmith.external.models.DatasourceConfiguration; import com.appsmith.external.models.Endpoint; +import com.appsmith.external.models.Property; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; import org.springframework.util.CollectionUtils; @@ -288,4 +289,22 @@ public class PluginUtils { public static List parseList(String arrayString) throws IOException { return objectMapper.readValue(arrayString, ArrayList.class); } + + public static T getValueSafelyFromPropertyList(List properties, int index, Class type, + T defaultValue) { + if (CollectionUtils.isEmpty(properties) || index > properties.size() - 1 || properties.get(index) == null + || properties.get(index).getValue() == null) { + return defaultValue; + } + + return (T) properties.get(index).getValue(); + } + + public static T getValueSafelyFromPropertyList(List properties, int index, Class type) { + return getValueSafelyFromPropertyList(properties, index, type, null); + } + + public static Object getValueSafelyFromPropertyList(List properties, int index) { + return getValueSafelyFromPropertyList(properties, index, Object.class); + } } diff --git a/app/server/appsmith-plugins/amazons3Plugin/src/main/java/com/external/utils/DatasourceUtils.java b/app/server/appsmith-plugins/amazons3Plugin/src/main/java/com/external/utils/DatasourceUtils.java index b72a313cf6..3279ebd669 100644 --- a/app/server/appsmith-plugins/amazons3Plugin/src/main/java/com/external/utils/DatasourceUtils.java +++ b/app/server/appsmith-plugins/amazons3Plugin/src/main/java/com/external/utils/DatasourceUtils.java @@ -1,8 +1,10 @@ package com.external.utils; +import com.amazonaws.ClientConfiguration; import com.amazonaws.auth.AWSStaticCredentialsProvider; import com.amazonaws.auth.BasicAWSCredentials; import com.amazonaws.client.builder.AwsClientBuilder; +import com.amazonaws.regions.Regions; import com.amazonaws.services.s3.AmazonS3ClientBuilder; import com.appsmith.external.exceptions.pluginExceptions.AppsmithPluginError; import com.appsmith.external.exceptions.pluginExceptions.AppsmithPluginException; @@ -17,6 +19,7 @@ import java.util.regex.Pattern; import static com.amazonaws.regions.Regions.DEFAULT_REGION; import static com.appsmith.external.exceptions.pluginExceptions.AppsmithPluginError.PLUGIN_ERROR; +import static com.appsmith.external.helpers.PluginUtils.getValueSafelyFromPropertyList; import static com.external.plugins.AmazonS3Plugin.CUSTOM_ENDPOINT_INDEX; import static com.external.plugins.AmazonS3Plugin.CUSTOM_ENDPOINT_REGION_PROPERTY_INDEX; import static com.external.plugins.AmazonS3Plugin.S3_SERVICE_PROVIDER_PROPERTY_INDEX; @@ -59,6 +62,7 @@ public class DatasourceUtils { WASABI ("wasabi"), DIGITAL_OCEAN_SPACES ("digital-ocean-spaces"), DREAM_OBJECTS ("dream-objects"), + MINIO ("minio"), OTHER ("other"); private String name; @@ -183,6 +187,31 @@ public class DatasourceUtils { region = getRegionFromEndpointPattern(endpoint, DREAM_OBJECTS_URL_ENDPOINT_PATTERN, DREAM_OBJECTS_REGION_GROUP_INDEX); + break; + case MINIO: + region = getUserProvidedRegion(properties); + if (StringUtils.isBlank(region)) { + /** + * Set a default region in case user has not provided a region. + * Minio server can be configured to work both ways - with or without region attribute. Hence, + * it is upto the user to know whether the Minio server they want to connect to has been + * configured with a region or not. + * As per my experimentation, in case the Minio server has not been configured with a region + * attribute, then any placeholder value will work. However, I am going with US_EAST_1 here + * since this the value that Minio documentation uses to show example applications. + * Ref: https://docs.min.io/docs/how-to-use-aws-sdk-for-java-with-minio-server.html + */ + region = Regions.US_EAST_1.getName(); + } + + ClientConfiguration clientConfiguration = new ClientConfiguration(); + clientConfiguration.setSignerOverride("AWSS3V4SignerType"); + + /* Ref: https://docs.min.io/docs/how-to-use-aws-sdk-for-java-with-minio-server.html */ + s3ClientBuilder = s3ClientBuilder + .withPathStyleAccessEnabled(true) + .withClientConfiguration(clientConfiguration); + break; default: region = (String) properties.get(CUSTOM_ENDPOINT_REGION_PROPERTY_INDEX).getValue(); @@ -195,6 +224,10 @@ public class DatasourceUtils { return s3ClientBuilder; } + private static String getUserProvidedRegion(List properties) { + return getValueSafelyFromPropertyList(properties, CUSTOM_ENDPOINT_REGION_PROPERTY_INDEX, String.class); + } + /** * This method checks if the S3 endpoint URL has correct format and extracts region information from it. * diff --git a/app/server/appsmith-plugins/amazons3Plugin/src/main/resources/editor/create.json b/app/server/appsmith-plugins/amazons3Plugin/src/main/resources/editor/create.json index 59e6d3777e..b6a7f0d540 100644 --- a/app/server/appsmith-plugins/amazons3Plugin/src/main/resources/editor/create.json +++ b/app/server/appsmith-plugins/amazons3Plugin/src/main/resources/editor/create.json @@ -41,7 +41,7 @@ "value": "YES" }, { - "label": "Text / Binary", + "label": "Text", "value": "NO" } ] diff --git a/app/server/appsmith-plugins/amazons3Plugin/src/main/resources/form.json b/app/server/appsmith-plugins/amazons3Plugin/src/main/resources/form.json index 4c15897d27..d769c029dd 100644 --- a/app/server/appsmith-plugins/amazons3Plugin/src/main/resources/form.json +++ b/app/server/appsmith-plugins/amazons3Plugin/src/main/resources/form.json @@ -38,6 +38,10 @@ "label": "DreamObjects", "value": "dream-objects" }, + { + "label": "MinIO", + "value": "minio" + }, { "label": "Other", "value": "other" @@ -48,6 +52,7 @@ "label": "Access Key", "configProperty": "datasourceConfiguration.authentication.username", "controlType": "INPUT_TEXT", + "isRequired": true, "initialValue": "" }, { @@ -56,14 +61,16 @@ "controlType": "INPUT_TEXT", "dataType": "PASSWORD", "initialValue": "", + "isRequired": true, "encrypted": true }, { - "label": "Endpoint URL", + "label": "Endpoint URL (with or without protocol and port no)", "configProperty": "datasourceConfiguration.endpoints[0].host", "controlType": "INPUT_TEXT", "initialValue": "", - "placeholderText": "user-storage.de-fra1.upcloudobjects.com", + "isRequired": true, + "placeholderText": "https://user-storage.de-fra1.upcloudobjects.com", "hidden": { "path": "datasourceConfiguration.properties[1].value", "comparison": "EQUALS", @@ -84,9 +91,19 @@ "initialValue": "", "placeholderText": "de-fra1", "hidden": { - "path": "datasourceConfiguration.properties[1].value", - "comparison": "NOT_EQUALS", - "value": "other" + "conditionType": "AND", + "conditions": [ + { + "path": "datasourceConfiguration.properties[1].value", + "comparison": "NOT_EQUALS", + "value": "other" + }, + { + "path": "datasourceConfiguration.properties[1].value", + "comparison": "NOT_EQUALS", + "value": "minio" + } + ] } } ]