diff --git a/app/server/appsmith-plugins/mongoPlugin/src/main/java/com/external/plugins/MongoPlugin.java b/app/server/appsmith-plugins/mongoPlugin/src/main/java/com/external/plugins/MongoPlugin.java index 68e516b2819..215d00636b0 100644 --- a/app/server/appsmith-plugins/mongoPlugin/src/main/java/com/external/plugins/MongoPlugin.java +++ b/app/server/appsmith-plugins/mongoPlugin/src/main/java/com/external/plugins/MongoPlugin.java @@ -109,6 +109,9 @@ import static com.external.plugins.constants.FieldName.SUCCESS; import static com.external.plugins.constants.FieldName.UPDATE_OPERATION; import static com.external.plugins.constants.FieldName.UPDATE_QUERY; +import static com.external.plugins.utils.DatasourceUtils.KEY_PASSWORD; +import static com.external.plugins.utils.DatasourceUtils.KEY_URI_DEFAULT_DBNAME; +import static com.external.plugins.utils.DatasourceUtils.KEY_USERNAME; import static com.external.plugins.utils.DatasourceUtils.buildClientURI; import static com.external.plugins.utils.DatasourceUtils.buildURIFromExtractedInfo; import static com.external.plugins.utils.DatasourceUtils.extractInfoFromConnectionStringURI; @@ -157,24 +160,18 @@ public class MongoPlugin extends BasePlugin { * We use this regex to find usage of special Mongo data types like ObjectId(...) wrapped inside double quotes * e.g. "ObjectId(...)". Case for single quotes e.g. 'ObjectId(...)' is not added because the way client sends * back the data to the API server it would be extremely uncommon to encounter this case. - * + *

* In the given regex E is replaced by the name of special data types before doing the match / find operation. * e.g. E will be replaced with ObjectId to find the occurrence of "ObjectId(...)" pattern. - * + *

* Example: for "[\"ObjectId('xyz')\"]": - * o group 1 will match "ObjectId(...)" - * o group 2 will match ObjectId(...) - * o group 3 will match 'xyz' - * o group 4 will match xyz + * o group 1 will match "ObjectId(...)" + * o group 2 will match ObjectId(...) + * o group 3 will match 'xyz' + * o group 4 will match xyz */ private static final String MONGODB_SPECIAL_TYPE_INSIDE_QUOTES_REGEX_TEMPLATE = "(\\\"(E\\((.*?((\\w|-|:|\\.|,|\\s)+).*?)?\\))\\\")"; - private static final String KEY_USERNAME = "username"; - - private static final String KEY_PASSWORD = "password"; - - private static final String KEY_URI_DBNAME = "dbName"; - private static final int DATASOURCE_CONFIG_MONGO_URI_PROPERTY_INDEX = 1; private static final Integer MONGO_COMMAND_EXCEPTION_UNAUTHORIZED_ERROR_CODE = 13; @@ -640,7 +637,6 @@ public Mono datasourceCreate(DatasourceConfiguration datasourceConf } - @Override public void datasourceDestroy(MongoClient mongoClient) { if (mongoClient != null) { @@ -668,18 +664,23 @@ public Set validateDatasource(DatasourceConfiguration datasourceConfigur if (extractedInfo == null) { invalids.add("Mongo Connection String URI does not seem to be in the correct format. " + "Please check the URI once."); - } else if (!isAuthenticated(authentication, mongoUri)) { - String mongoUriWithHiddenPassword = buildURIFromExtractedInfo(extractedInfo, "****"); - properties.get(DATASOURCE_CONFIG_MONGO_URI_PROPERTY_INDEX).setValue(mongoUriWithHiddenPassword); - authentication = (authentication == null) ? new DBAuth() : authentication; - authentication.setUsername((String) extractedInfo.get(KEY_USERNAME)); - authentication.setPassword((String) extractedInfo.get(KEY_PASSWORD)); - authentication.setDatabaseName((String) extractedInfo.get(KEY_URI_DBNAME)); - datasourceConfiguration.setAuthentication(authentication); - - // remove any default db set via form auto-fill via browser - if (datasourceConfiguration.getConnection() != null) { - datasourceConfiguration.getConnection().setDefaultDatabaseName(null); + } else { + if (extractedInfo.get(KEY_URI_DEFAULT_DBNAME) == null) { + invalids.add("Missing default database name."); + } + if (!isAuthenticated(authentication, mongoUri)) { + String mongoUriWithHiddenPassword = buildURIFromExtractedInfo(extractedInfo, "****"); + properties.get(DATASOURCE_CONFIG_MONGO_URI_PROPERTY_INDEX).setValue(mongoUriWithHiddenPassword); + authentication = (authentication == null) ? new DBAuth() : authentication; + authentication.setUsername((String) extractedInfo.get(KEY_USERNAME)); + authentication.setPassword((String) extractedInfo.get(KEY_PASSWORD)); + authentication.setDatabaseName((String) extractedInfo.get(KEY_URI_DEFAULT_DBNAME)); + datasourceConfiguration.setAuthentication(authentication); + + // remove any default db set via form auto-fill via browser + if (datasourceConfiguration.getConnection() != null) { + datasourceConfiguration.getConnection().setDefaultDatabaseName(null); + } } } } @@ -720,7 +721,7 @@ public Set validateDatasource(DatasourceConfiguration datasourceConfigur } if (!StringUtils.hasLength(authentication.getDatabaseName())) { - invalids.add("Missing database name."); + invalids.add("Missing default database name."); } } @@ -860,7 +861,7 @@ public Object substituteValueInInput(int index, Object... args) { String jsonBody = (String) input; DataType dataType = stringToKnownMongoDBDataTypeConverter(value); - return DataTypeStringUtils.jsonSmartReplacementPlaceholderWithValue(jsonBody, value,dataType, insertedParams, this); + return DataTypeStringUtils.jsonSmartReplacementPlaceholderWithValue(jsonBody, value, dataType, insertedParams, this); } /** @@ -904,6 +905,7 @@ public Mono execute(MongoClient mongoClient, * This method coverts Mongo plugin's form data to Mongo's native query. Currently, it is meant to help users * switch easily from form based input to raw input mode by providing a readily available translation of the * form data to raw query. + * * @return Mongo's native/raw query set at path `formData.formToNativeQuery.data` */ @Override diff --git a/app/server/appsmith-plugins/mongoPlugin/src/main/java/com/external/plugins/utils/DatasourceUtils.java b/app/server/appsmith-plugins/mongoPlugin/src/main/java/com/external/plugins/utils/DatasourceUtils.java index 71f2514a136..c730b45a0f3 100644 --- a/app/server/appsmith-plugins/mongoPlugin/src/main/java/com/external/plugins/utils/DatasourceUtils.java +++ b/app/server/appsmith-plugins/mongoPlugin/src/main/java/com/external/plugins/utils/DatasourceUtils.java @@ -44,17 +44,17 @@ public class DatasourceUtils { private static final int REGEX_GROUP_TAIL = 6; - private static final String KEY_USERNAME = "username"; + public static final String KEY_USERNAME = "username"; - private static final String KEY_PASSWORD = "password"; + public static final String KEY_PASSWORD = "password"; - private static final String KEY_HOST_PORT = "hostPort"; + public static final String KEY_HOST_PORT = "hostPort"; - private static final String KEY_URI_HEAD = "uriHead"; + public static final String KEY_URI_HEAD = "uriHead"; - private static final String KEY_URI_TAIL = "uriTail"; + public static final String KEY_URI_TAIL = "uriTail"; - private static final String KEY_URI_DBNAME = "dbName"; + public static final String KEY_URI_DEFAULT_DBNAME = "defaultDbName"; private static final String YES = "Yes"; @@ -94,7 +94,7 @@ public static Map extractInfoFromConnectionStringURI(String uri, String regex) { extractedInfoMap.put(KEY_USERNAME, matcher.group(REGEX_GROUP_USERNAME)); extractedInfoMap.put(KEY_PASSWORD, matcher.group(REGEX_GROUP_PASSWORD)); extractedInfoMap.put(KEY_HOST_PORT, matcher.group(REGEX_HOST_PORT)); - extractedInfoMap.put(KEY_URI_DBNAME, matcher.group(REGEX_GROUP_DBNAME)); + extractedInfoMap.put(KEY_URI_DEFAULT_DBNAME, matcher.group(REGEX_GROUP_DBNAME)); extractedInfoMap.put(KEY_URI_TAIL, matcher.group(REGEX_GROUP_TAIL)); return extractedInfoMap; } @@ -113,7 +113,7 @@ public static String buildURIFromExtractedInfo(Map extractedInfo, String passwor userInfo += "@"; } - final String dbInfo = "/" + (extractedInfo.get(KEY_URI_DBNAME) == null ? "" : extractedInfo.get(KEY_URI_DBNAME)); + final String dbInfo = "/" + (extractedInfo.get(KEY_URI_DEFAULT_DBNAME) == null ? "" : extractedInfo.get(KEY_URI_DEFAULT_DBNAME)); String tailInfo = (String) (extractedInfo.get(KEY_URI_TAIL) == null ? "" : extractedInfo.get(KEY_URI_TAIL)); tailInfo = "?" + buildURITail(tailInfo); diff --git a/app/server/appsmith-plugins/mongoPlugin/src/main/java/com/external/plugins/utils/MongoPluginUtils.java b/app/server/appsmith-plugins/mongoPlugin/src/main/java/com/external/plugins/utils/MongoPluginUtils.java index a7e64aa4339..ecaa6f7612c 100644 --- a/app/server/appsmith-plugins/mongoPlugin/src/main/java/com/external/plugins/utils/MongoPluginUtils.java +++ b/app/server/appsmith-plugins/mongoPlugin/src/main/java/com/external/plugins/utils/MongoPluginUtils.java @@ -107,15 +107,23 @@ private static MongoCommand getMongoCommand(ActionConfiguration actionConfigurat } public static String getDatabaseName(DatasourceConfiguration datasourceConfiguration) { + String databaseName = null; + // Explicitly set default database. - String databaseName = datasourceConfiguration.getConnection().getDefaultDatabaseName(); + if (datasourceConfiguration.getConnection() != null) { + databaseName = datasourceConfiguration.getConnection().getDefaultDatabaseName(); + } // If that's not available, pick the authentication database. final DBAuth authentication = (DBAuth) datasourceConfiguration.getAuthentication(); - if (StringUtils.isEmpty(databaseName) && authentication != null) { + if (!StringUtils.hasLength(databaseName) && authentication != null) { databaseName = authentication.getDatabaseName(); } + if (databaseName == null) { + throw new AppsmithPluginException(AppsmithPluginError.PLUGIN_DATASOURCE_ARGUMENT_ERROR, "Missing default database name."); + } + return databaseName; } diff --git a/app/server/appsmith-plugins/mongoPlugin/src/test/java/com/external/plugins/MongoPluginTest.java b/app/server/appsmith-plugins/mongoPlugin/src/test/java/com/external/plugins/MongoPluginTest.java index 242ba6ce965..b4b2d8cbe27 100644 --- a/app/server/appsmith-plugins/mongoPlugin/src/test/java/com/external/plugins/MongoPluginTest.java +++ b/app/server/appsmith-plugins/mongoPlugin/src/test/java/com/external/plugins/MongoPluginTest.java @@ -2835,4 +2835,18 @@ public void testStaleConnectionOnMongoSocketWriteExceptionOnGetStructure() { .expectErrorMatches(throwable -> throwable instanceof StaleConnectionException) .verify(); } + + @Test + public void testValidateDatasource_withoutDefaultDBInURIString_returnsInvalid() { + final DatasourceConfiguration datasourceConfiguration = new DatasourceConfiguration(); + List properties = new ArrayList<>(); + properties.add(new Property("isUriString", "Yes")); + properties.add(new Property("uriString", "mongodb://user:pass@url.net/")); + datasourceConfiguration.setProperties(properties); + + final Set strings = pluginExecutor.validateDatasource(datasourceConfiguration); + + assertEquals(1, strings.size()); + assertTrue(strings.contains("Missing default database name.")); + } } diff --git a/app/server/appsmith-plugins/mongoPlugin/src/test/java/com/external/plugins/utils/MongoPluginUtilsTest.java b/app/server/appsmith-plugins/mongoPlugin/src/test/java/com/external/plugins/utils/MongoPluginUtilsTest.java new file mode 100644 index 00000000000..a6241b71260 --- /dev/null +++ b/app/server/appsmith-plugins/mongoPlugin/src/test/java/com/external/plugins/utils/MongoPluginUtilsTest.java @@ -0,0 +1,22 @@ +package com.external.plugins.utils; + +import com.appsmith.external.exceptions.pluginExceptions.AppsmithPluginException; +import com.appsmith.external.models.DatasourceConfiguration; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; + +public class MongoPluginUtilsTest { + + @Test + public void testGetDatabaseName_withoutDatabaseName_throwsDatasourceError() { + final AppsmithPluginException exception = assertThrows( + AppsmithPluginException.class, + () -> MongoPluginUtils.getDatabaseName(new DatasourceConfiguration()) + ); + + assertEquals("Missing default database name.", exception.getMessage()); + + } +} \ No newline at end of file