From 3622d8b0d3f3e0950bf5e151afd292faafb56df3 Mon Sep 17 00:00:00 2001 From: Arpit Mohan Date: Tue, 5 Nov 2019 10:40:09 +0000 Subject: [PATCH] Converting actionConfiguration to a string to extract mustache keys Also making jsonPathKeys a read-only field. Cannot be written via the API. --- .../external/models/ActionConfiguration.java | 2 +- .../com/external/plugins/RestApiPlugin.java | 5 +- .../com/appsmith/server/domains/Action.java | 6 +- .../server/services/ActionServiceImpl.java | 102 +++++++++++++++++- 4 files changed, 105 insertions(+), 10 deletions(-) diff --git a/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/models/ActionConfiguration.java b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/models/ActionConfiguration.java index f7a836d360..51c5b93ac4 100644 --- a/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/models/ActionConfiguration.java +++ b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/models/ActionConfiguration.java @@ -31,7 +31,7 @@ public class ActionConfiguration { String path; List headers; List queryParameters; - Map body; + String body; HttpMethod httpMethod; // DB action fields diff --git a/app/server/appsmith-plugins/restApiPlugin/src/main/java/com/external/plugins/RestApiPlugin.java b/app/server/appsmith-plugins/restApiPlugin/src/main/java/com/external/plugins/RestApiPlugin.java index 6216ee7651..76f99c8386 100644 --- a/app/server/appsmith-plugins/restApiPlugin/src/main/java/com/external/plugins/RestApiPlugin.java +++ b/app/server/appsmith-plugins/restApiPlugin/src/main/java/com/external/plugins/RestApiPlugin.java @@ -39,10 +39,7 @@ public class RestApiPlugin extends BasePlugin { public Mono execute(Object connection, ResourceConfiguration resourceConfiguration, ActionConfiguration actionConfiguration) { - Map requestBody = actionConfiguration.getBody(); - if (requestBody == null) { - requestBody = (Map) new HashMap(); - } + String requestBody = actionConfiguration.getBody(); String path = (actionConfiguration.getPath() == null) ? "" : actionConfiguration.getPath(); String url = resourceConfiguration.getUrl() + path; diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/Action.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/Action.java index f6b19ee31b..e0b424a705 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/Action.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/Action.java @@ -1,13 +1,14 @@ package com.appsmith.server.domains; import com.appsmith.external.models.ActionConfiguration; +import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; import lombok.ToString; import org.springframework.data.mongodb.core.mapping.Document; -import java.util.List; +import java.util.Set; @Getter @Setter @@ -30,5 +31,6 @@ public class Action extends BaseDomain { // This is a list of keys that the client whose values the client needs to send during action execution. // These are the Mustache keys that the server will replace before invoking the API - List jsonPathKeys; + @JsonProperty(access = JsonProperty.Access.READ_ONLY) + Set jsonPathKeys; } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ActionServiceImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ActionServiceImpl.java index 066fd4e1d3..8867f2ab30 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ActionServiceImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ActionServiceImpl.java @@ -6,6 +6,7 @@ import com.appsmith.external.models.Param; import com.appsmith.external.models.ResourceConfiguration; import com.appsmith.external.plugins.PluginExecutor; import com.appsmith.server.constants.AnalyticsEvents; +import com.appsmith.server.constants.FieldName; import com.appsmith.server.domains.Action; import com.appsmith.server.domains.Page; import com.appsmith.server.domains.PageAction; @@ -15,6 +16,7 @@ import com.appsmith.server.dtos.ExecuteActionDTO; import com.appsmith.server.exceptions.AppsmithError; import com.appsmith.server.exceptions.AppsmithException; import com.appsmith.server.repositories.ActionRepository; +import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.github.mustachejava.DefaultMustacheFactory; import com.github.mustachejava.Mustache; @@ -34,11 +36,17 @@ import java.io.StringReader; import java.io.StringWriter; import java.io.Writer; import java.util.ArrayList; -import java.util.HashMap; +import java.util.Collection; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import java.util.stream.Collectors; +import static com.appsmith.server.helpers.BeanCopyUtils.copyNewFieldValuesIntoOldObject; + @Slf4j @Service public class ActionServiceImpl extends BaseService implements ActionService { @@ -51,6 +59,9 @@ public class ActionServiceImpl extends BaseService + * Calling the base function would make redundant DB calls and slow down this API unnecessarily. + * + * @param id + * @param action + * @return + */ + @Override + public Mono update(String id, Action action) { + if (id == null) { + return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, FieldName.ID)); + } + + return repository.findById(id) + .switchIfEmpty(Mono.error(new AppsmithException(AppsmithError.NO_RESOURCE_FOUND, "action", id))) + .map(dbAction -> { + copyNewFieldValuesIntoOldObject(action, dbAction); + return dbAction; + }) + .map(act -> extractAndSetJsonPathKeys(act)) + .flatMap(repository::save) + .map(act -> { + analyticsService + .sendEvent(AnalyticsEvents.UPDATE + "_" + act.getClass().getSimpleName().toUpperCase(), + act); + return act; + } + ); + } + @Override public Mono create(@NotNull Action action) { if (action.getId() != null) { @@ -92,11 +137,62 @@ public class ActionServiceImpl extends BaseService { action.setPluginId(plugin.getId()); return action; - }) + }).map(act -> extractAndSetJsonPathKeys(act)) .flatMap(super::create) .switchIfEmpty(Mono.error(new AppsmithException(AppsmithError.REPOSITORY_SAVE_FAILED))); } + private Set extractMustacheKeys(String template) { + if (template == null || template.isEmpty()) { + return new HashSet<>(); + } + + Matcher matcher = pattern.matcher(template); + + if (matcher.groupCount() > 0) { + Set collect = matcher.results() + .map(result -> result.group(1)) + .collect(Collectors.toSet()); + return collect; + } + return new HashSet<>(); + } + + /** + * This function extracts all the mustache template keys (as per the regex) and returns them to the calling fxn + * This set of keys is stored separately in the field `jsonPathKeys` in the action object. The client + * uses the set `jsonPathKeys` to simplify it's value substitution. + * + * @param action + * @return + */ + private Set extractKeysFromAction(Action action) { + if(action.getActionConfiguration() == null) { + return new HashSet<>(); + } + + // Convert the object to String as a preparation to send it to mustache extraction + try { + String actionConfigStr = objectMapper.writeValueAsString(action.getActionConfiguration()); + return extractMustacheKeys(actionConfigStr); + } catch (JsonProcessingException e) { + log.error("Exception caught while extracting mustache keys from action configuration. ", e); + } + return new HashSet<>(); + } + + /** + * This function extracts the mustache keys and sets them in the field jsonPathKeys in the action object + * + * @param action + * @return + */ + private Action extractAndSetJsonPathKeys(Action action) { + Set keys = extractKeysFromAction(action); + action.setJsonPathKeys(keys); + return action; + } + public Mono bindPageToAction(Action action, String pageId) { Mono pageMono = pageService.findById(pageId); action.setPageId(pageId); @@ -208,7 +304,7 @@ public class ActionServiceImpl extends BaseService