From ef2f2d77514a9ca84c648cbe8a0a2b5d3bd7b582 Mon Sep 17 00:00:00 2001 From: Trisha Anand Date: Tue, 14 Sep 2021 18:34:49 +0530 Subject: [PATCH] feat: Smart Substitution for Google Sheets Plugin (#7397) --- .../external/plugins/GoogleSheetsPlugin.java | 106 +++++++++++++++++- .../src/main/resources/editor.json | 95 ++++++++++++++-- .../src/main/resources/setting.json | 36 ++++++ 3 files changed, 222 insertions(+), 15 deletions(-) create mode 100644 app/server/appsmith-plugins/googleSheetsPlugin/src/main/resources/setting.json diff --git a/app/server/appsmith-plugins/googleSheetsPlugin/src/main/java/com/external/plugins/GoogleSheetsPlugin.java b/app/server/appsmith-plugins/googleSheetsPlugin/src/main/java/com/external/plugins/GoogleSheetsPlugin.java index e39643d0b4..dad3831a1d 100644 --- a/app/server/appsmith-plugins/googleSheetsPlugin/src/main/java/com/external/plugins/GoogleSheetsPlugin.java +++ b/app/server/appsmith-plugins/googleSheetsPlugin/src/main/java/com/external/plugins/GoogleSheetsPlugin.java @@ -1,7 +1,10 @@ package com.external.plugins; +import com.appsmith.external.dtos.ExecuteActionDTO; import com.appsmith.external.exceptions.pluginExceptions.AppsmithPluginError; import com.appsmith.external.exceptions.pluginExceptions.AppsmithPluginException; +import com.appsmith.external.helpers.DataTypeStringUtils; +import com.appsmith.external.helpers.MustacheHelper; import com.appsmith.external.models.ActionConfiguration; import com.appsmith.external.models.ActionExecutionResult; import com.appsmith.external.models.DatasourceConfiguration; @@ -10,6 +13,7 @@ import com.appsmith.external.models.OAuth2; import com.appsmith.external.models.Property; import com.appsmith.external.plugins.BasePlugin; import com.appsmith.external.plugins.PluginExecutor; +import com.appsmith.external.plugins.SmartSubstitutionInterface; import com.external.config.GoogleSheetsMethodStrategy; import com.external.config.Method; import com.external.config.MethodConfig; @@ -26,9 +30,15 @@ import reactor.core.Exceptions; import reactor.core.publisher.Mono; import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; +import static java.lang.Boolean.TRUE; + public class GoogleSheetsPlugin extends BasePlugin { // Setting max content length. This would've been coming from `spring.codec.max-in-memory-size` property if the @@ -44,12 +54,83 @@ public class GoogleSheetsPlugin extends BasePlugin { @Slf4j @Extension - public static class GoogleSheetsPluginExecutor implements PluginExecutor { + public static class GoogleSheetsPluginExecutor implements PluginExecutor, SmartSubstitutionInterface { + + private static final int SMART_JSON_SUBSTITUTION_INDEX = 13; + + private static final Set jsonFields = new HashSet<>(Arrays.asList( + "rowObject", + "rowObjects" + )); @Override - public Mono execute(Void connection, - DatasourceConfiguration datasourceConfiguration, - ActionConfiguration actionConfiguration) { + public Mono executeParameterized(Void connection, + ExecuteActionDTO executeActionDTO, + DatasourceConfiguration datasourceConfiguration, + ActionConfiguration actionConfiguration) { + + Boolean smartBsonSubstitution; + final List properties = actionConfiguration.getPluginSpecifiedTemplates(); + List> parameters = new ArrayList<>(); + + // Default smart substitution to true + if (CollectionUtils.isEmpty(properties)) { + smartBsonSubstitution = true; + } else if (properties.size() > SMART_JSON_SUBSTITUTION_INDEX && + properties.get(SMART_JSON_SUBSTITUTION_INDEX) != null) { + Object ssubValue = properties.get(SMART_JSON_SUBSTITUTION_INDEX).getValue(); + if (ssubValue instanceof Boolean) { + smartBsonSubstitution = (Boolean) ssubValue; + } else if (ssubValue instanceof String) { + smartBsonSubstitution = Boolean.parseBoolean((String) ssubValue); + } else { + smartBsonSubstitution = true; + } + } else { + smartBsonSubstitution = true; + } + + try { + // Smartly substitute in Json fields and replace all the bindings with values. + if (TRUE.equals(smartBsonSubstitution)) { + properties.stream().parallel().forEach(property -> { + if (property.getValue() != null) { + String propertyValue = String.valueOf(property.getValue()); + String propertyKey = property.getKey(); + + if (jsonFields.contains(propertyKey)) { + // First extract all the bindings in order + List mustacheKeysInOrder = MustacheHelper.extractMustacheKeysInOrder(propertyValue); + // Replace all the bindings with a placeholder + String updatedValue = MustacheHelper.replaceMustacheWithPlaceholder(propertyValue, mustacheKeysInOrder); + + updatedValue = (String) smartSubstitutionOfBindings(updatedValue, + mustacheKeysInOrder, + executeActionDTO.getParams(), + parameters); + + property.setValue(updatedValue); + } + } + }); + } + } catch (AppsmithPluginException e) { + // Initializing object for error condition + ActionExecutionResult errorResult = new ActionExecutionResult(); + errorResult.setStatusCode(AppsmithPluginError.PLUGIN_ERROR.getAppErrorCode().toString()); + errorResult.setIsExecutionSuccess(false); + errorResult.setErrorInfo(e); + return Mono.just(errorResult); + } + + prepareConfigurationsForExecution(executeActionDTO, actionConfiguration, datasourceConfiguration); + + return this.executeCommon(connection, datasourceConfiguration, actionConfiguration); + } + + public Mono executeCommon(Void connection, + DatasourceConfiguration datasourceConfiguration, + ActionConfiguration actionConfiguration) { // Initializing object for error condition ActionExecutionResult errorResult = new ActionExecutionResult(); @@ -163,6 +244,12 @@ public class GoogleSheetsPlugin extends BasePlugin { }); } + @Override + public Mono execute(Void connection, DatasourceConfiguration datasourceConfiguration, ActionConfiguration actionConfiguration) { + // Unused function + return Mono.error(new AppsmithPluginException(AppsmithPluginError.PLUGIN_ERROR, "Unsupported Operation")); + } + @Override public Mono datasourceCreate(DatasourceConfiguration datasourceConfiguration) { return Mono.empty(); @@ -191,5 +278,16 @@ public class GoogleSheetsPlugin extends BasePlugin { actionConfiguration.setPluginSpecifiedTemplates(pluginSpecifiedTemplates); return execute(null, datasourceConfiguration, actionConfiguration); } + + @Override + public Object substituteValueInInput(int index, + String binding, + String value, + Object input, + List> insertedParams, + Object... args) { + String jsonBody = (String) input; + return DataTypeStringUtils.jsonSmartReplacementPlaceholderWithValue(jsonBody, value, insertedParams); + } } } \ No newline at end of file diff --git a/app/server/appsmith-plugins/googleSheetsPlugin/src/main/resources/editor.json b/app/server/appsmith-plugins/googleSheetsPlugin/src/main/resources/editor.json index d4a16f5db5..2fba66e8fe 100644 --- a/app/server/appsmith-plugins/googleSheetsPlugin/src/main/resources/editor.json +++ b/app/server/appsmith-plugins/googleSheetsPlugin/src/main/resources/editor.json @@ -381,12 +381,48 @@ "label": "Row Object", "configProperty": "actionConfiguration.pluginSpecifiedTemplates[9].value", "controlType": "QUERY_DYNAMIC_TEXT", + "evaluationSubstitutionType": "SMART_SUBSTITUTE", "hidden": { - "path": "actionConfiguration.pluginSpecifiedTemplates[0].value", - "comparison": "NOT_IN", - "value": [ - "APPEND", - "UPDATE" + "conditionType": "OR", + "conditions" : [ + { + "path": "actionConfiguration.pluginSpecifiedTemplates[0].value", + "comparison": "NOT_IN", + "value": [ + "APPEND", + "UPDATE" + ] + }, + { + "path": "actionConfiguration.pluginSpecifiedTemplates[13].value", + "comparison": "EQUALS", + "value": false + } + ] + }, + "placeholderText": "{{\n {\n ...Table1.selectedRow, \n columnName: Input1.text\n }\n}}" + }, + { + "label": "Row Object", + "configProperty": "actionConfiguration.pluginSpecifiedTemplates[9].value", + "controlType": "QUERY_DYNAMIC_TEXT", + "evaluationSubstitutionType": "TEMPLATE", + "hidden": { + "conditionType": "OR", + "conditions":[ + { + "path": "actionConfiguration.pluginSpecifiedTemplates[0].value", + "comparison": "NOT_IN", + "value": [ + "APPEND", + "UPDATE" + ] + }, + { + "path": "actionConfiguration.pluginSpecifiedTemplates[13].value", + "comparison": "EQUALS", + "value": true + } ] }, "placeholderText": "{{\n {\n ...Table1.selectedRow, \n columnName: Input1.text\n }\n}}" @@ -402,13 +438,50 @@ "label": "Row Objects", "configProperty": "actionConfiguration.pluginSpecifiedTemplates[10].value", "controlType": "QUERY_DYNAMIC_TEXT", + "evaluationSubstitutionType": "PARAMETER", "hidden": { - "path": "actionConfiguration.pluginSpecifiedTemplates[0].value", - "comparison": "NOT_IN", - "value": [ - "CREATE", - "BULK_APPEND", - "BULK_UPDATE" + "conditionType": "OR", + "conditions" : [ + { + "path": "actionConfiguration.pluginSpecifiedTemplates[0].value", + "comparison": "NOT_IN", + "value": [ + "CREATE", + "BULK_APPEND", + "BULK_UPDATE" + ] + }, + { + "path": "actionConfiguration.pluginSpecifiedTemplates[13].value", + "comparison": "EQUALS", + "value": false + } + ] + }, + "placeholderText": "{{\n Table1.selectedRows.map((row) => {\n return { ...row, columnName: Input1.text }\n })\n}}" + }, + { + "label": "Row Objects", + "configProperty": "actionConfiguration.pluginSpecifiedTemplates[10].value", + "controlType": "QUERY_DYNAMIC_TEXT", + "evaluationSubstitutionType": "TEMPLATE", + "hidden": { + "conditionType": "OR", + "conditions" : [ + { + "path": "actionConfiguration.pluginSpecifiedTemplates[0].value", + "comparison": "NOT_IN", + "value": [ + "CREATE", + "BULK_APPEND", + "BULK_UPDATE" + ] + }, + { + "path": "actionConfiguration.pluginSpecifiedTemplates[13].value", + "comparison": "EQUALS", + "value": true + } ] }, "placeholderText": "{{\n Table1.selectedRows.map((row) => {\n return { ...row, columnName: Input1.text }\n })\n}}" diff --git a/app/server/appsmith-plugins/googleSheetsPlugin/src/main/resources/setting.json b/app/server/appsmith-plugins/googleSheetsPlugin/src/main/resources/setting.json new file mode 100644 index 0000000000..16315aada1 --- /dev/null +++ b/app/server/appsmith-plugins/googleSheetsPlugin/src/main/resources/setting.json @@ -0,0 +1,36 @@ +{ + "setting": [ + { + "sectionName": "", + "id": 1, + "children": [ + { + "label": "Run query on page load", + "configProperty": "executeOnLoad", + "controlType": "SWITCH", + "info": "Will refresh data each time the page is loaded" + }, + { + "label": "Request confirmation before running query", + "configProperty": "confirmBeforeExecute", + "controlType": "SWITCH", + "info": "Ask confirmation from the user each time before refreshing data" + }, + { + "label": "Smart JSON Substitution", + "info": "Turning on this property fixes the JSON substitution of bindings in the Row objects by adding/removing quotes intelligently and reduces developer errors", + "configProperty": "actionConfiguration.pluginSpecifiedTemplates[13].value", + "controlType": "SWITCH", + "initialValue": true + }, + { + "label": "Query timeout (in milliseconds)", + "info": "Maximum time after which the query will return", + "configProperty": "actionConfiguration.timeoutInMillisecond", + "controlType": "INPUT_TEXT", + "dataType": "NUMBER" + } + ] + } + ] +}