diff --git a/app/client/src/components/editorComponents/ActionCreator/index.tsx b/app/client/src/components/editorComponents/ActionCreator/index.tsx index 257e726115..43d342d5f0 100644 --- a/app/client/src/components/editorComponents/ActionCreator/index.tsx +++ b/app/client/src/components/editorComponents/ActionCreator/index.tsx @@ -391,7 +391,8 @@ function getIntegrationOptionsWithChildren( const apis = actions.filter( (action) => action.config.pluginType === PluginType.API || - action.config.pluginType === PluginType.SAAS, + action.config.pluginType === PluginType.SAAS || + action.config.pluginType === PluginType.REMOTE, ); const option = options.find( (option) => option.value === ActionType.integration, diff --git a/app/client/src/components/editorComponents/CodeEditor/generateQuickCommands.tsx b/app/client/src/components/editorComponents/CodeEditor/generateQuickCommands.tsx index 10d90fb318..801b81ff94 100644 --- a/app/client/src/components/editorComponents/CodeEditor/generateQuickCommands.tsx +++ b/app/client/src/components/editorComponents/CodeEditor/generateQuickCommands.tsx @@ -104,6 +104,7 @@ function Command(props: { DB: , API: , SAAS: , + REMOTE: , JS: , }[props.pluginType]} {props.imgSrc && } diff --git a/app/client/src/components/editorComponents/LightningMenu/hooks.ts b/app/client/src/components/editorComponents/LightningMenu/hooks.ts index 96eaf0aec2..4b7e5a7030 100644 --- a/app/client/src/components/editorComponents/LightningMenu/hooks.ts +++ b/app/client/src/components/editorComponents/LightningMenu/hooks.ts @@ -30,7 +30,11 @@ export const useActions = () => { .map((action) => action.config); const saas: Action[] = actions - .filter((action) => action.config.pluginType === PluginType.SAAS) + .filter( + (action) => + action.config.pluginType === PluginType.SAAS || + action.config.pluginType === PluginType.REMOTE, + ) .map((action) => action.config); return { apis, queries, saas }; diff --git a/app/client/src/constants/AppsmithActionConstants/ActionConstants.tsx b/app/client/src/constants/AppsmithActionConstants/ActionConstants.tsx index e1ea8b925d..0d3586fbdb 100644 --- a/app/client/src/constants/AppsmithActionConstants/ActionConstants.tsx +++ b/app/client/src/constants/AppsmithActionConstants/ActionConstants.tsx @@ -119,6 +119,7 @@ export const defaultActionSettings: Record = { [PluginType.API]: apiActionSettingsConfig, [PluginType.DB]: queryActionSettingsConfig, [PluginType.SAAS]: saasActionSettingsConfig, + [PluginType.REMOTE]: saasActionSettingsConfig, [PluginType.JS]: [], }; @@ -126,6 +127,7 @@ export const defaultActionEditorConfigs: Record = { [PluginType.API]: apiActionEditorConfig, [PluginType.DB]: [], [PluginType.SAAS]: [], + [PluginType.REMOTE]: [], [PluginType.JS]: [], }; @@ -136,5 +138,6 @@ export const defaultActionDependenciesConfig: Record< [PluginType.API]: apiActionDependencyConfig, [PluginType.DB]: {}, [PluginType.SAAS]: {}, + [PluginType.REMOTE]: {}, [PluginType.JS]: {}, }; diff --git a/app/client/src/entities/Action/index.ts b/app/client/src/entities/Action/index.ts index c4761a707c..24040b6e9e 100644 --- a/app/client/src/entities/Action/index.ts +++ b/app/client/src/entities/Action/index.ts @@ -7,6 +7,7 @@ export enum PluginType { DB = "DB", SAAS = "SAAS", JS = "JS", + REMOTE = "REMOTE", } export enum PaginationType { @@ -93,6 +94,11 @@ export interface SaaSAction extends BaseAction { actionConfiguration: any; datasource: StoredDatasource; } +export interface RemoteAction extends BaseAction { + pluginType: PluginType.REMOTE; + actionConfiguration: any; + datasource: StoredDatasource; +} export interface EmbeddedApiAction extends BaseApiAction { datasource: EmbeddedRestDatasource; @@ -127,4 +133,4 @@ export type ActionViewMode = { timeoutInMillisecond?: number; }; -export type Action = ApiAction | QueryAction | SaaSAction; +export type Action = ApiAction | QueryAction | SaaSAction | RemoteAction; diff --git a/app/client/src/pages/Editor/Explorer/Actions/helpers.tsx b/app/client/src/pages/Editor/Explorer/Actions/helpers.tsx index 13d4c48eed..922aacc688 100644 --- a/app/client/src/pages/Editor/Explorer/Actions/helpers.tsx +++ b/app/client/src/pages/Editor/Explorer/Actions/helpers.tsx @@ -55,7 +55,7 @@ export type ActionGroupConfig = { export const ACTION_PLUGIN_MAP: Array = [ { groupName: "Datasources", - types: [PluginType.API, PluginType.SAAS, PluginType.DB], + types: [PluginType.API, PluginType.SAAS, PluginType.DB, PluginType.REMOTE], icon: dbQueryIcon, key: generateReactKey(), getURL: ( @@ -72,7 +72,10 @@ export const ACTION_PLUGIN_MAP: Array = [ plugin.packageName, id, )}`; - } else if (pluginType === PluginType.DB) { + } else if ( + pluginType === PluginType.DB || + pluginType === PluginType.REMOTE + ) { return `${QUERIES_EDITOR_ID_URL(applicationId, pageId, id)}`; } else { return `${API_EDITOR_ID_URL(applicationId, pageId, id)}`; @@ -164,6 +167,9 @@ export const getPluginGroups = ( ...entries.filter( (entry: any) => entry.config.pluginType === PluginType.DB, ), + ...entries.filter( + (entry: any) => entry.config.pluginType === PluginType.REMOTE, + ), ] : entries; diff --git a/app/client/src/pages/Editor/IntegrationEditor/NewApi.tsx b/app/client/src/pages/Editor/IntegrationEditor/NewApi.tsx index 514342e691..1f164bd5f0 100644 --- a/app/client/src/pages/Editor/IntegrationEditor/NewApi.tsx +++ b/app/client/src/pages/Editor/IntegrationEditor/NewApi.tsx @@ -294,7 +294,9 @@ function NewApiScreen(props: Props) { )} {plugins - .filter((p) => p.type === PluginType.SAAS) + .filter( + (p) => p.type === PluginType.SAAS || p.type === PluginType.REMOTE, + ) .map((p) => ( { plugins: allPlugins, runErrorMessage, pluginIds: getPluginIdsOfPackageNames(state, PLUGIN_PACKAGE_DBS), - dataSources: getDBDatasources(state), + dataSources: getDBAndRemoteDatasources(state), responses: getActionResponses(state), isRunning: state.ui.queryPane.isRunning[props.match.params.queryId], isDeleting: state.ui.queryPane.isDeleting[props.match.params.queryId], diff --git a/app/client/src/sagas/QueryPaneSagas.ts b/app/client/src/sagas/QueryPaneSagas.ts index 9bb76942c0..0f64b91d2f 100644 --- a/app/client/src/sagas/QueryPaneSagas.ts +++ b/app/client/src/sagas/QueryPaneSagas.ts @@ -160,7 +160,7 @@ function* handleQueryCreatedSaga(actionPayload: ReduxAction) { pluginId, pluginType, } = actionPayload.payload; - if (pluginType === PluginType.DB) { + if (pluginType === PluginType.DB || pluginType === PluginType.REMOTE) { yield put(initialize(QUERY_EDITOR_FORM_NAME, actionPayload.payload)); const applicationId = yield select(getCurrentApplicationId); const pageId = yield select(getCurrentPageId); @@ -182,8 +182,10 @@ function* handleQueryCreatedSaga(actionPayload: ReduxAction) { function* handleDatasourceCreatedSaga(actionPayload: ReduxAction) { const plugin = yield select(getPlugin, actionPayload.payload.pluginId); + debugger; // Only look at db plugins - if (plugin.type !== PluginType.DB) return; + if (plugin.type !== PluginType.DB && plugin.type !== PluginType.REMOTE) + return; const applicationId = yield select(getCurrentApplicationId); const pageId = yield select(getCurrentPageId); diff --git a/app/client/src/selectors/entitiesSelector.ts b/app/client/src/selectors/entitiesSelector.ts index 180bad80e3..ac21aea257 100644 --- a/app/client/src/selectors/entitiesSelector.ts +++ b/app/client/src/selectors/entitiesSelector.ts @@ -181,6 +181,13 @@ export const getDBPlugins = createSelector(getPlugins, (plugins) => plugins.filter((plugin) => plugin.type === PluginType.DB), ); +export const getDBAndRemotePlugins = createSelector(getPlugins, (plugins) => + plugins.filter( + (plugin) => + plugin.type === PluginType.DB || plugin.type === PluginType.REMOTE, + ), +); + export const getDatasourceByPluginId = (state: AppState, pluginId: string) => state.entities.datasources.list.filter((d) => d.pluginId === pluginId); @@ -197,6 +204,19 @@ export const getDBDatasources = createSelector( }, ); +export const getDBAndRemoteDatasources = createSelector( + getDBAndRemotePlugins, + getEntities, + (plugins, entities) => { + const datasources = entities.datasources.list; + const pluginIds = plugins.map((plugin) => plugin.id); + + return datasources.filter((datasource) => + pluginIds.includes(datasource.pluginId), + ); + }, +); + export const getQueryName = (state: AppState, actionId: string): string => { const action = state.entities.actions.find((action: ActionData) => { return action.config.id === actionId; diff --git a/app/server/appsmith-interfaces/pom.xml b/app/server/appsmith-interfaces/pom.xml index 944db31b54..61b59468c2 100644 --- a/app/server/appsmith-interfaces/pom.xml +++ b/app/server/appsmith-interfaces/pom.xml @@ -131,6 +131,10 @@ h2 1.4.200 + + org.springframework + spring-webflux + diff --git a/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/dtos/DatasourceDTO.java b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/dtos/DatasourceDTO.java new file mode 100644 index 0000000000..58416df76c --- /dev/null +++ b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/dtos/DatasourceDTO.java @@ -0,0 +1,14 @@ +package com.appsmith.external.dtos; + +import com.appsmith.external.models.DatasourceConfiguration; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; + +@AllArgsConstructor +@Getter +@Setter +public class DatasourceDTO { + String id; + DatasourceConfiguration datasourceConfiguration; +} diff --git a/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/dtos/ExecutePluginDTO.java b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/dtos/ExecutePluginDTO.java new file mode 100644 index 0000000000..a5ae2ff669 --- /dev/null +++ b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/dtos/ExecutePluginDTO.java @@ -0,0 +1,18 @@ +package com.appsmith.external.dtos; + +import com.appsmith.external.models.ActionConfiguration; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class ExecutePluginDTO { + String installationKey; + String pluginName; + String pluginVersion; + String actionTemplateName; + String datasourceTemplateName; + DatasourceDTO datasource; + ActionConfiguration actionConfiguration; + ExecuteActionDTO executeActionDTO; +} 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 fdc7fd8e65..942aac80b8 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 @@ -5,6 +5,7 @@ import lombok.NoArgsConstructor; import lombok.Setter; import lombok.ToString; import org.hibernate.validator.constraints.Range; +import org.springframework.data.annotation.Transient; import org.springframework.data.mongodb.core.mapping.Document; import org.springframework.http.HttpMethod; @@ -75,6 +76,9 @@ public class ActionConfiguration implements AppsmithDomain { */ Map formData; + @Transient + String templateName; + public void setTimeoutInMillisecond(String timeoutInMillisecond) { try { this.timeoutInMillisecond = Integer.valueOf(timeoutInMillisecond); diff --git a/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/models/AuthenticationDTO.java b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/models/AuthenticationDTO.java index 423da04b3f..7002d5b535 100644 --- a/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/models/AuthenticationDTO.java +++ b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/models/AuthenticationDTO.java @@ -7,7 +7,6 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.Setter; -import org.springframework.data.annotation.Transient; import reactor.core.publisher.Mono; import java.util.Set; @@ -24,7 +23,6 @@ import java.util.Set; @JsonSubTypes.Type(value = DBAuth.class, name = Authentication.DB_AUTH), @JsonSubTypes.Type(value = OAuth2.class, name = Authentication.OAUTH2), @JsonSubTypes.Type(value = BasicAuth.class, name = Authentication.BASIC), - @JsonSubTypes.Type(value = BasicAuth.class, name = Authentication.BASIC), @JsonSubTypes.Type(value = ApiKeyAuth.class, name = Authentication.API_KEY), @JsonSubTypes.Type(value = BearerTokenAuth.class, name = Authentication.BEARER_TOKEN) }) @@ -39,7 +37,6 @@ public class AuthenticationDTO implements AppsmithDomain { SUCCESS }; - @Transient String authenticationType; AuthenticationStatus authenticationStatus; diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/Datasource.java b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/models/Datasource.java similarity index 93% rename from app/server/appsmith-server/src/main/java/com/appsmith/server/domains/Datasource.java rename to app/server/appsmith-interfaces/src/main/java/com/appsmith/external/models/Datasource.java index 3c5919c9b9..a874e082c3 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/Datasource.java +++ b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/models/Datasource.java @@ -1,8 +1,5 @@ -package com.appsmith.server.domains; +package com.appsmith.external.models; -import com.appsmith.external.models.BaseDomain; -import com.appsmith.external.models.DatasourceConfiguration; -import com.appsmith.external.models.DatasourceStructure; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; @@ -32,6 +29,8 @@ public class Datasource extends BaseDomain { String organizationId; + String templateName; + DatasourceConfiguration datasourceConfiguration; @JsonProperty(access = JsonProperty.Access.READ_ONLY) diff --git a/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/models/OAuth2.java b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/models/OAuth2.java index d04c1bf71c..7de665abfb 100644 --- a/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/models/OAuth2.java +++ b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/models/OAuth2.java @@ -37,8 +37,10 @@ public class OAuth2 extends AuthenticationDTO { Type grantType; + // Send tokens as query params if false Boolean isTokenHeader = false; + // Send auth details in body if false Boolean isAuthorizationHeader = false; String clientId; diff --git a/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/services/SharedConfig.java b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/services/SharedConfig.java index 8f1eaa630a..8774fcda7b 100644 --- a/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/services/SharedConfig.java +++ b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/services/SharedConfig.java @@ -5,4 +5,6 @@ public interface SharedConfig { int getCodecSize(); int getMaxResponseSize(); + + String getRemoteExecutionUrl(); } diff --git a/app/server/appsmith-plugins/pom.xml b/app/server/appsmith-plugins/pom.xml index 1daab7260e..8a60d6026a 100644 --- a/app/server/appsmith-plugins/pom.xml +++ b/app/server/appsmith-plugins/pom.xml @@ -30,5 +30,6 @@ snowflakePlugin arangoDBPlugin jsPlugin + saasPlugin \ No newline at end of file diff --git a/app/server/appsmith-plugins/postgresPlugin/src/test/java/com/external/plugins/PostgresPluginTest.java b/app/server/appsmith-plugins/postgresPlugin/src/test/java/com/external/plugins/PostgresPluginTest.java index a9490fca25..f93c558c0e 100644 --- a/app/server/appsmith-plugins/postgresPlugin/src/test/java/com/external/plugins/PostgresPluginTest.java +++ b/app/server/appsmith-plugins/postgresPlugin/src/test/java/com/external/plugins/PostgresPluginTest.java @@ -65,6 +65,11 @@ public class PostgresPluginTest { public int getMaxResponseSize() { return 10000; } + + @Override + public String getRemoteExecutionUrl() { + return ""; + } } diff --git a/app/server/appsmith-plugins/restApiPlugin/src/test/java/com/external/plugins/RestApiPluginTest.java b/app/server/appsmith-plugins/restApiPlugin/src/test/java/com/external/plugins/RestApiPluginTest.java index afcdda0b69..e39eeaa174 100644 --- a/app/server/appsmith-plugins/restApiPlugin/src/test/java/com/external/plugins/RestApiPluginTest.java +++ b/app/server/appsmith-plugins/restApiPlugin/src/test/java/com/external/plugins/RestApiPluginTest.java @@ -57,6 +57,11 @@ public class RestApiPluginTest { public int getMaxResponseSize() { return 10000; } + + @Override + public String getRemoteExecutionUrl() { + return ""; + } } RestApiPlugin.RestApiPluginExecutor pluginExecutor = new RestApiPlugin.RestApiPluginExecutor(new MockSharedConfig()); diff --git a/app/server/appsmith-plugins/saasPlugin/plugin.properties b/app/server/appsmith-plugins/saasPlugin/plugin.properties new file mode 100644 index 0000000000..198f0f4feb --- /dev/null +++ b/app/server/appsmith-plugins/saasPlugin/plugin.properties @@ -0,0 +1,5 @@ +plugin.id=saas-plugin +plugin.class=com.external.plugins.SaasPlugin +plugin.version=1.0-SNAPSHOT +plugin.provider=tech@appsmith.com +plugin.dependencies= diff --git a/app/server/appsmith-plugins/saasPlugin/pom.xml b/app/server/appsmith-plugins/saasPlugin/pom.xml new file mode 100644 index 0000000000..cef34082a4 --- /dev/null +++ b/app/server/appsmith-plugins/saasPlugin/pom.xml @@ -0,0 +1,120 @@ + + + + 4.0.0 + + com.external.plugins + saasPlugin + 1.0-SNAPSHOT + + saasPlugin + + + UTF-8 + 11 + ${java.version} + ${java.version} + saas-plugin + com.external.plugins.SaasPlugin + 1.0-SNAPSHOT + tech@appsmith.com + + + + + + + org.pf4j + pf4j-spring + 0.7.0 + provided + + + + com.appsmith + interfaces + 1.0-SNAPSHOT + provided + + + + org.springframework + spring-core + 5.2.3.RELEASE + provided + + + + org.springframework + spring-web + 5.2.3.RELEASE + provided + + + + org.springframework + spring-webflux + 5.2.3.RELEASE + + + io.projectreactor + reactor-core + + + org.springframework + spring-core + + + org.springframework + spring-web + + + + + org.projectlombok + lombok + RELEASE + compile + + + org.projectlombok + lombok + RELEASE + compile + + + + + + + + org.apache.maven.plugins + maven-shade-plugin + 3.2.4 + + false + + + + ${plugin.id} + ${plugin.class} + ${plugin.version} + ${plugin.provider} + + + + + + + package + + shade + + + + + + + + diff --git a/app/server/appsmith-plugins/saasPlugin/src/main/java/com/external/helpers/BodyReceiver.java b/app/server/appsmith-plugins/saasPlugin/src/main/java/com/external/helpers/BodyReceiver.java new file mode 100644 index 0000000000..a84b90a847 --- /dev/null +++ b/app/server/appsmith-plugins/saasPlugin/src/main/java/com/external/helpers/BodyReceiver.java @@ -0,0 +1,228 @@ +package com.external.helpers; + +import com.appsmith.external.exceptions.pluginExceptions.AppsmithPluginError; +import com.appsmith.external.exceptions.pluginExceptions.AppsmithPluginException; +import org.reactivestreams.Publisher; +import org.reactivestreams.Subscriber; +import org.reactivestreams.Subscription; +import org.springframework.core.ResolvableType; +import org.springframework.core.io.buffer.DataBuffer; +import org.springframework.core.io.buffer.DataBufferFactory; +import org.springframework.http.HttpCookie; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.http.ReactiveHttpOutputMessage; +import org.springframework.http.client.reactive.ClientHttpRequest; +import org.springframework.http.codec.HttpMessageWriter; +import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.util.MultiValueMap; +import org.springframework.web.reactive.function.BodyInserter; +import reactor.core.publisher.Mono; + +import java.net.URI; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; +import java.util.function.Supplier; + +/** + * This receiver essentially instantiates a custom ClientHttpRequest that stores the request body via a subscriber + * The BodyInserter instance from our original request inserts into this subscriber that we can then retrieve + * using receiveValue. + * + * We do this so that the received value that we display to the user is exactly the same as + * the body tht is sent over the wire + */ +public class BodyReceiver { + private static final Object DUMMY = new Object(); + + private final AtomicReference reference = new AtomicReference<>(DUMMY); + + public Object receiveValue(BodyInserter bodyInserter) { + demandValueFrom(bodyInserter); + + return receivedValue(); + } + + private void demandValueFrom(BodyInserter bodyInserter) { + final BodyInserter inserter = + (BodyInserter) bodyInserter; + + inserter.insert( + MinimalHttpOutputMessage.INSTANCE, + new SingleWriterContext(new WriteToConsumer<>(reference::set)) + ); + } + + private Object receivedValue() { + Object value = reference.get(); + reference.set(DUMMY); + + Object validatedValue; + + if (value == DUMMY) { + throw new AppsmithPluginException( + AppsmithPluginError.PLUGIN_ERROR, + "Value was not received, check if your inserter worked properly"); + } else { + validatedValue = value; + } + + return validatedValue; + } + + static class WriteToConsumer implements HttpMessageWriter { + + private final Consumer consumer; + private final List mediaTypes; + + WriteToConsumer(Consumer consumer) { + this.consumer = consumer; + this.mediaTypes = Collections.singletonList(MediaType.ALL); + } + + @Override + public List getWritableMediaTypes() { + return mediaTypes; + } + + @Override + public boolean canWrite(ResolvableType elementType, MediaType mediaType) { + return true; + } + + @Override + public Mono write( + Publisher inputStream, + ResolvableType elementType, + MediaType mediaType, + ReactiveHttpOutputMessage message, + Map hints + ) { + inputStream.subscribe(new OneValueConsumption<>(consumer)); + return Mono.empty(); + } + } + + static class MinimalHttpOutputMessage implements ClientHttpRequest { + + public static MinimalHttpOutputMessage INSTANCE = new MinimalHttpOutputMessage(); + + private MinimalHttpOutputMessage() { + } + + @Override + public HttpHeaders getHeaders() { + return HttpHeaders.EMPTY; + } + + @Override + public DataBufferFactory bufferFactory() { + return null; + } + + @Override + public void beforeCommit(Supplier> action) { + } + + @Override + public boolean isCommitted() { + return false; + } + + @Override + public Mono writeWith(Publisher body) { + return null; + } + + @Override + public Mono writeAndFlushWith(Publisher> body) { + return null; + } + + @Override + public Mono setComplete() { + return null; + } + + @Override + public HttpMethod getMethod() { + return null; + } + + @Override + public URI getURI() { + return null; + } + + @Override + public MultiValueMap getCookies() { + return null; + } + } + + static class OneValueConsumption implements Subscriber { + + private final Consumer consumer; + private int remainedAccepts; + + public OneValueConsumption(Consumer consumer) { + this.consumer = Objects.requireNonNull(consumer); + this.remainedAccepts = 1; + } + + @Override + public void onSubscribe(Subscription s) { + s.request(1); + } + + @Override + public void onNext(T o) { + if (remainedAccepts > 0) { + consumer.accept(o); + remainedAccepts -= 1; + } else { + throw new AppsmithPluginException(AppsmithPluginError.PLUGIN_ERROR, "No more values can be consumed"); + } + } + + @Override + public void onError(Throwable t) { + throw new AppsmithPluginException(AppsmithPluginError.PLUGIN_ERROR, "Single value was not consumed", t); + } + + @Override + public void onComplete() { + // nothing + } + } + + static class SingleWriterContext implements BodyInserter.Context { + + private final List> singleWriterList; + + SingleWriterContext(HttpMessageWriter writer) { + this.singleWriterList = List.of(writer); + } + + @Override + public List> messageWriters() { + return singleWriterList; + } + + @Override + public Optional serverRequest() { + return Optional.empty(); + } + + @Override + public Map hints() { + return null; + } + } +} diff --git a/app/server/appsmith-plugins/saasPlugin/src/main/java/com/external/helpers/RequestCaptureFilter.java b/app/server/appsmith-plugins/saasPlugin/src/main/java/com/external/helpers/RequestCaptureFilter.java new file mode 100644 index 0000000000..ee2cdb945a --- /dev/null +++ b/app/server/appsmith-plugins/saasPlugin/src/main/java/com/external/helpers/RequestCaptureFilter.java @@ -0,0 +1,147 @@ +package com.external.helpers; + +import com.appsmith.external.models.ActionConfiguration; +import com.appsmith.external.models.ActionExecutionRequest; +import com.appsmith.external.models.Property; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.Getter; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.lang.NonNull; +import org.springframework.util.CollectionUtils; +import org.springframework.util.LinkedCaseInsensitiveMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.reactive.function.client.ClientRequest; +import org.springframework.web.reactive.function.client.ClientResponse; +import org.springframework.web.reactive.function.client.ExchangeFilterFunction; +import org.springframework.web.reactive.function.client.ExchangeFunction; +import reactor.core.publisher.Mono; + +import java.net.URI; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; + +import static org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE; + +/** + * This filter captures the request that was sent out via WebClient so that the execution response can + * accurately represent the actual request used + */ +@Getter +public class RequestCaptureFilter implements ExchangeFilterFunction { + + private ClientRequest request; + private final ObjectMapper objectMapper; + private final BodyReceiver bodyReceiver = new BodyReceiver(); + + public RequestCaptureFilter(ObjectMapper objectMapper) { + this.objectMapper = objectMapper; + } + + @Override + @NonNull + public Mono filter(@NonNull ClientRequest request, ExchangeFunction next) { + this.request = request; + return next.exchange(request); + } + + public ActionExecutionRequest populateRequestFields(ActionExecutionRequest existing) { + + final ActionExecutionRequest actionExecutionRequest = new ActionExecutionRequest(); + actionExecutionRequest.setUrl(request.url().toString()); + actionExecutionRequest.setHttpMethod(request.method()); + MultiValueMap headers = CollectionUtils.toMultiValueMap(new LinkedCaseInsensitiveMap<>(8, Locale.ENGLISH)); + AtomicBoolean isMultipart = new AtomicBoolean(false); + request.headers().forEach((header, value) -> { + if (HttpHeaders.AUTHORIZATION.equalsIgnoreCase(header) || "api_key".equalsIgnoreCase(header)) { + headers.add(header, "****"); + } else { + headers.addAll(header, value); + } + if (HttpHeaders.CONTENT_TYPE.equalsIgnoreCase(header) && MULTIPART_FORM_DATA_VALUE.equalsIgnoreCase(value.get(0))) { + isMultipart.set(true); + } + }); + actionExecutionRequest.setHeaders(objectMapper.valueToTree(headers)); + + actionExecutionRequest.setRequestParams(existing.getRequestParams()); + actionExecutionRequest.setExecutionParameters(existing.getExecutionParameters()); + actionExecutionRequest.setProperties(existing.getProperties()); + + // Apart from multipart, refer to the request that was actually sent + if (!isMultipart.get()) { + actionExecutionRequest.setBody(bodyReceiver.receiveValue(this.request.body())); + } else { + actionExecutionRequest.setBody(existing.getBody()); + } + + return actionExecutionRequest; + } + + public static ActionExecutionRequest populateRequestFields(ActionConfiguration actionConfiguration, + URI uri, + List> insertedParams, + ObjectMapper objectMapper) { + + ActionExecutionRequest actionExecutionRequest = new ActionExecutionRequest(); + + if (!insertedParams.isEmpty()) { + final Map requestData = new HashMap<>(); + requestData.put("smart-substitution-parameters", insertedParams); + actionExecutionRequest.setProperties(requestData); + } + + AtomicReference reqContentType = new AtomicReference<>(); + + if (actionConfiguration.getHeaders() != null) { + MultiValueMap reqMultiMap = CollectionUtils.toMultiValueMap(new LinkedCaseInsensitiveMap<>(8, Locale.ENGLISH)); + + actionConfiguration.getHeaders() + .forEach(header -> { + if (HttpHeaders.CONTENT_TYPE.equalsIgnoreCase(header.getKey())) { + reqContentType.set((String) header.getValue()); + } + reqMultiMap.put(header.getKey(), Arrays.asList((String) header.getValue())); + }); + actionExecutionRequest.setHeaders(objectMapper.valueToTree(reqMultiMap)); + } + + // If the body is set, then use that field as the request body by default + if (actionConfiguration.getBody() != null) { + actionExecutionRequest.setBody(actionConfiguration.getBody()); + } + + if (MediaType.APPLICATION_FORM_URLENCODED_VALUE.equals(reqContentType.get())) { + final List bodyFormData = actionConfiguration.getBodyFormData(); + Map bodyDataMap = new HashMap<>(); + bodyFormData.forEach(property -> bodyDataMap.put(property.getKey(), property.getValue())); + actionExecutionRequest.setBody(bodyDataMap); + } else if (MediaType.MULTIPART_FORM_DATA_VALUE.equals(reqContentType.get())) { + final List bodyFormData = actionConfiguration.getBodyFormData(); + Map bodyDataMap = new HashMap<>(); + bodyFormData.forEach(property -> { + if ("FILE".equalsIgnoreCase(property.getType())) { + bodyDataMap.put(property.getKey(), ""); + } else { + bodyDataMap.put(property.getKey(), property.getValue()); + } + }); + actionExecutionRequest.setBody(bodyDataMap); + } + + if (actionConfiguration.getHttpMethod() != null) { + actionExecutionRequest.setHttpMethod(actionConfiguration.getHttpMethod()); + } + + if (uri != null) { + actionExecutionRequest.setUrl(uri.toString()); + } + + return actionExecutionRequest; + } +} diff --git a/app/server/appsmith-plugins/saasPlugin/src/main/java/com/external/plugins/SaasPlugin.java b/app/server/appsmith-plugins/saasPlugin/src/main/java/com/external/plugins/SaasPlugin.java new file mode 100644 index 0000000000..411b8245c3 --- /dev/null +++ b/app/server/appsmith-plugins/saasPlugin/src/main/java/com/external/plugins/SaasPlugin.java @@ -0,0 +1,219 @@ +package com.external.plugins; + +import com.appsmith.external.dtos.ExecutePluginDTO; +import com.appsmith.external.exceptions.pluginExceptions.AppsmithPluginError; +import com.appsmith.external.exceptions.pluginExceptions.AppsmithPluginException; +import com.appsmith.external.models.ActionConfiguration; +import com.appsmith.external.models.ActionExecutionRequest; +import com.appsmith.external.models.ActionExecutionResult; +import com.appsmith.external.models.DatasourceConfiguration; +import com.appsmith.external.models.DatasourceTestResult; +import com.appsmith.external.plugins.BasePlugin; +import com.appsmith.external.plugins.PluginExecutor; +import com.appsmith.external.plugins.SmartSubstitutionInterface; +import com.appsmith.external.services.SharedConfig; +import com.external.helpers.RequestCaptureFilter; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.MapperFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.pf4j.Extension; +import org.pf4j.PluginWrapper; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.client.reactive.ClientHttpRequest; +import org.springframework.http.codec.json.Jackson2JsonEncoder; +import org.springframework.web.reactive.function.BodyInserter; +import org.springframework.web.reactive.function.BodyInserters; +import org.springframework.web.reactive.function.client.ClientResponse; +import org.springframework.web.reactive.function.client.ExchangeStrategies; +import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.web.util.UriComponentsBuilder; +import reactor.core.Exceptions; +import reactor.core.publisher.Mono; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.List; +import java.util.Set; + +import static org.springframework.http.HttpHeaders.CONTENT_TYPE; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; + +public class SaasPlugin extends BasePlugin { + private static final int MAX_REDIRECTS = 5; + + public SaasPlugin(PluginWrapper wrapper) { + super(wrapper); + } + + @Extension + public static class SaasPluginExecutor implements PluginExecutor, SmartSubstitutionInterface { + + private final SharedConfig sharedConfig; + // Setting max content length. This would've been coming from `spring.codec.max-in-memory-size` property if the + // `WebClient` instance was loaded as an auto-wired bean. + private final ExchangeStrategies EXCHANGE_STRATEGIES; + private final ObjectMapper saasObjectMapper = new ObjectMapper(); + + public SaasPluginExecutor(SharedConfig sharedConfig) { + this.sharedConfig = sharedConfig; + saasObjectMapper.disable(MapperFeature.USE_ANNOTATIONS); + saasObjectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + saasObjectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + this.EXCHANGE_STRATEGIES = ExchangeStrategies + .builder() + .codecs(clientDefaultCodecsConfigurer -> { + clientDefaultCodecsConfigurer.defaultCodecs().jackson2JsonEncoder(new Jackson2JsonEncoder(saasObjectMapper, MediaType.APPLICATION_JSON)); + clientDefaultCodecsConfigurer.defaultCodecs().maxInMemorySize(sharedConfig.getCodecSize()); + }) + .build(); + } + + @Override + public Mono execute(ExecutePluginDTO connection, DatasourceConfiguration datasourceConfiguration, ActionConfiguration actionConfiguration) { + // Initializing object for error condition + ActionExecutionResult errorResult = new ActionExecutionResult(); + + final String datasourceConfigurationCommand = datasourceConfiguration.getAuthentication().getAuthenticationType(); + if (datasourceConfigurationCommand == null || datasourceConfigurationCommand.isEmpty()) { + return Mono.error(new AppsmithPluginException(AppsmithPluginError.PLUGIN_DATASOURCE_ARGUMENT_ERROR, "Missing template name for datasource")); + } + + final String actionConfigurationCommand = (String) actionConfiguration.getFormData().get("command"); + if (actionConfigurationCommand == null || actionConfigurationCommand.isEmpty()) { + return Mono.error(new AppsmithPluginException(AppsmithPluginError.PLUGIN_EXECUTE_ARGUMENT_ERROR, "Missing template name for action")); + } + + connection.setActionConfiguration(actionConfiguration); + connection.setDatasourceTemplateName(datasourceConfigurationCommand); + connection.setActionTemplateName(actionConfigurationCommand); + + UriComponentsBuilder uriBuilder = UriComponentsBuilder.newInstance(); + URI uri = null; + try { + uri = uriBuilder.uri(new URI(sharedConfig.getRemoteExecutionUrl())).build(true).toUri(); + } catch (URISyntaxException e) { + e.printStackTrace(); + } + + ActionExecutionRequest actionExecutionRequest = + RequestCaptureFilter.populateRequestFields(actionConfiguration, uri, List.of(), objectMapper); + + + // Initializing webClient to be used for http call + WebClient.Builder webClientBuilder = WebClient.builder(); + webClientBuilder.defaultHeader(CONTENT_TYPE, APPLICATION_JSON_VALUE); + final RequestCaptureFilter requestCaptureFilter = new RequestCaptureFilter(objectMapper); + webClientBuilder.filter(requestCaptureFilter); + + WebClient client = webClientBuilder.exchangeStrategies(EXCHANGE_STRATEGIES).build(); + + String valueAsString = ""; + try { + valueAsString = saasObjectMapper.writeValueAsString(connection); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + Object requestBodyObj = BodyInserters.fromValue(valueAsString); + + // Triggering the actual REST API call + return httpCall(client, HttpMethod.POST, uri, requestBodyObj, 0, APPLICATION_JSON_VALUE) + .flatMap(clientResponse -> clientResponse.toEntity(byte[].class)) + .map(stringResponseEntity -> { + final HttpStatus statusCode = stringResponseEntity.getStatusCode(); + byte[] body = stringResponseEntity.getBody(); + if (statusCode.is2xxSuccessful()) { + try { + return saasObjectMapper.readValue(body, ActionExecutionResult.class); + } catch (IOException e) { + throw Exceptions.propagate( + new AppsmithPluginException( + AppsmithPluginError.PLUGIN_JSON_PARSE_ERROR, + body, + e.getMessage() + ) + ); + } + } else { + throw Exceptions.propagate( + new AppsmithPluginException( + AppsmithPluginError.PLUGIN_ERROR, + body + ) + ); + } + }) + .onErrorResume(error -> { + errorResult.setRequest(requestCaptureFilter.populateRequestFields(actionExecutionRequest)); + errorResult.setIsExecutionSuccess(false); + errorResult.setErrorInfo(error); + return Mono.just(errorResult); + }); + + } + + private Mono httpCall(WebClient webClient, HttpMethod httpMethod, URI uri, Object requestBody, + int iteration, String contentType) { + if (iteration == MAX_REDIRECTS) { + return Mono.error(new AppsmithPluginException( + AppsmithPluginError.PLUGIN_ERROR, + "Exceeded the HTTP redirect limits of " + MAX_REDIRECTS + )); + } + + assert requestBody instanceof BodyInserter; + BodyInserter finalRequestBody = (BodyInserter) requestBody; + + return webClient + .method(httpMethod) + .uri(uri) + .body((BodyInserter) finalRequestBody) + .exchange() + .doOnError(e -> Mono.error(new AppsmithPluginException(AppsmithPluginError.PLUGIN_ERROR, e))) + .flatMap(response -> { + if (response.statusCode().is3xxRedirection()) { + String redirectUrl = response.headers().header("Location").get(0); + /** + * TODO + * In case the redirected URL is not absolute (complete), create the new URL using the relative path + * This particular scenario is seen in the URL : https://rickandmortyapi.com/api/character + * It redirects to partial URI : /api/character/ + * In this scenario we should convert the partial URI to complete URI + */ + URI redirectUri; + try { + redirectUri = new URI(redirectUrl); + } catch (URISyntaxException e) { + return Mono.error(new AppsmithPluginException(AppsmithPluginError.PLUGIN_ERROR, e)); + } + return httpCall(webClient, httpMethod, redirectUri, finalRequestBody, iteration + 1, + contentType); + } + return Mono.just(response); + }); + } + + @Override + public Mono datasourceCreate(DatasourceConfiguration datasourceConfiguration) { + return Mono.empty(); + } + + @Override + public void datasourceDestroy(ExecutePluginDTO connection) { + } + + @Override + public Set validateDatasource(DatasourceConfiguration datasourceConfiguration) { + return Set.of(); + } + + @Override + public Mono testDatasource(DatasourceConfiguration datasourceConfiguration) { + return Mono.empty(); + } + } +} \ No newline at end of file diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/acl/AclPermission.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/acl/AclPermission.java index d9685dd1b3..82a8d3e930 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/acl/AclPermission.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/acl/AclPermission.java @@ -5,7 +5,7 @@ import com.appsmith.server.domains.Action; import com.appsmith.server.domains.Application; import com.appsmith.server.domains.Comment; import com.appsmith.server.domains.CommentThread; -import com.appsmith.server.domains.Datasource; +import com.appsmith.external.models.Datasource; import com.appsmith.server.domains.Organization; import com.appsmith.server.domains.Page; import com.appsmith.server.domains.User; diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/SharedConfigImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/SharedConfigImpl.java index 346e9cb33c..cfd8b8f4d0 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/SharedConfigImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/SharedConfigImpl.java @@ -15,6 +15,9 @@ public class SharedConfigImpl implements SharedConfig { @Value("${appsmith.plugin.response.size.max:5}") private float maxPluginResponseSize = 5; + @Value("${appsmith.cloud_services.base_url}") + private String cloudServicesBaseUrl; + @Override public int getCodecSize() { return this.CODEC_SIZE * 1024 * 1024; @@ -24,4 +27,9 @@ public class SharedConfigImpl implements SharedConfig { public int getMaxResponseSize() { return (int) (this.maxPluginResponseSize * 1024 * 1024); } + + @Override + public String getRemoteExecutionUrl() { + return cloudServicesBaseUrl + "/api/v1/actions/execute"; + } } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/controllers/DatasourceController.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/controllers/DatasourceController.java index 6c6f86c5b1..43076f4cbf 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/controllers/DatasourceController.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/controllers/DatasourceController.java @@ -5,7 +5,7 @@ import com.appsmith.external.models.DatasourceStructure; import com.appsmith.external.models.DatasourceTestResult; import com.appsmith.external.models.Property; import com.appsmith.server.constants.Url; -import com.appsmith.server.domains.Datasource; +import com.appsmith.external.models.Datasource; import com.appsmith.server.dtos.AuthorizationCodeCallbackDTO; import com.appsmith.server.dtos.MockDataSet; import com.appsmith.server.dtos.MockDataSource; diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/controllers/SaasController.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/controllers/SaasController.java index 910187490c..f3fa52087e 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/controllers/SaasController.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/controllers/SaasController.java @@ -1,7 +1,7 @@ package com.appsmith.server.controllers; import com.appsmith.server.constants.Url; -import com.appsmith.server.domains.Datasource; +import com.appsmith.external.models.Datasource; import com.appsmith.server.dtos.ResponseDTO; import com.appsmith.server.solutions.AuthenticationService; import lombok.extern.slf4j.Slf4j; 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 1703b7966e..14d2fe9605 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 @@ -2,6 +2,7 @@ package com.appsmith.server.domains; import com.appsmith.external.models.ActionConfiguration; import com.appsmith.external.models.BaseDomain; +import com.appsmith.external.models.Datasource; import com.appsmith.external.models.Property; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/ApplicationJson.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/ApplicationJson.java index 5cc80f3e40..06479c6f25 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/ApplicationJson.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/ApplicationJson.java @@ -1,5 +1,6 @@ package com.appsmith.server.domains; +import com.appsmith.external.models.Datasource; import com.appsmith.external.models.DecryptedSensitiveFields; import lombok.Getter; import lombok.Setter; diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/Plugin.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/Plugin.java index 3f62dfa3e8..f1d579e6b8 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/Plugin.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/Plugin.java @@ -30,6 +30,8 @@ public class Plugin extends BaseDomain { String packageName; + String pluginName; + String jarLocation; String iconLocation; @@ -69,6 +71,14 @@ public class Plugin extends BaseDomain { Boolean allowUserDatasources = true; + boolean isRemotePlugin = false; + + // Stores the equivalent of editor.json for remote plugins + Map actionUiConfig; + + // Stores the equivalent of form.json for remote plugins + Map datasourceUiConfig; + @Transient Map templates; diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/PluginType.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/PluginType.java index db7e8bd94c..85ac8af0e4 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/PluginType.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/PluginType.java @@ -1,5 +1,5 @@ package com.appsmith.server.domains; public enum PluginType { - DB, API, JS, SAAS + DB, API, JS, SAAS, REMOTE } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/dtos/ActionDTO.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/dtos/ActionDTO.java index 002b36921b..6fe4a9ff04 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/dtos/ActionDTO.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/dtos/ActionDTO.java @@ -4,7 +4,7 @@ import com.appsmith.external.models.ActionConfiguration; import com.appsmith.external.models.Policy; import com.appsmith.external.models.Property; import com.appsmith.server.domains.ActionProvider; -import com.appsmith.server.domains.Datasource; +import com.appsmith.external.models.Datasource; import com.appsmith.server.domains.Documentation; import com.appsmith.server.domains.PluginType; import com.fasterxml.jackson.annotation.JsonIgnore; diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/PolicyUtils.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/PolicyUtils.java index c27c430856..814a1145c7 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/PolicyUtils.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/PolicyUtils.java @@ -7,7 +7,7 @@ import com.appsmith.server.acl.PolicyGenerator; import com.appsmith.server.domains.ActionCollection; import com.appsmith.server.domains.Application; import com.appsmith.server.domains.CommentThread; -import com.appsmith.server.domains.Datasource; +import com.appsmith.external.models.Datasource; import com.appsmith.server.domains.NewAction; import com.appsmith.server.domains.NewPage; import com.appsmith.server.domains.User; diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/DatabaseChangelog.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/DatabaseChangelog.java index 0c91880745..9b150fa286 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/DatabaseChangelog.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/DatabaseChangelog.java @@ -5,9 +5,11 @@ import com.appsmith.external.models.ActionConfiguration; import com.appsmith.external.models.BaseDomain; import com.appsmith.external.models.Connection; import com.appsmith.external.models.DBAuth; +import com.appsmith.external.models.Datasource; import com.appsmith.external.models.DatasourceConfiguration; import com.appsmith.external.models.Policy; import com.appsmith.external.models.Property; +import com.appsmith.external.models.QDatasource; import com.appsmith.external.models.SSLDetails; import com.appsmith.external.services.EncryptionService; import com.appsmith.server.acl.AclPermission; @@ -18,7 +20,6 @@ import com.appsmith.server.domains.Action; import com.appsmith.server.domains.Application; import com.appsmith.server.domains.Collection; import com.appsmith.server.domains.Config; -import com.appsmith.server.domains.Datasource; import com.appsmith.server.domains.Group; import com.appsmith.server.domains.InviteUser; import com.appsmith.server.domains.Layout; @@ -33,7 +34,6 @@ import com.appsmith.server.domains.Plugin; import com.appsmith.server.domains.PluginType; import com.appsmith.server.domains.QApplication; import com.appsmith.server.domains.QConfig; -import com.appsmith.server.domains.QDatasource; import com.appsmith.server.domains.QNewAction; import com.appsmith.server.domains.QOrganization; import com.appsmith.server.domains.QPlugin; diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/CustomDatasourceRepository.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/CustomDatasourceRepository.java index c1e46d8b85..5729a36dd2 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/CustomDatasourceRepository.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/CustomDatasourceRepository.java @@ -2,7 +2,7 @@ package com.appsmith.server.repositories; import com.appsmith.external.models.DatasourceStructure; import com.appsmith.server.acl.AclPermission; -import com.appsmith.server.domains.Datasource; +import com.appsmith.external.models.Datasource; import com.mongodb.client.result.UpdateResult; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/CustomDatasourceRepositoryImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/CustomDatasourceRepositoryImpl.java index e6b416649e..c00a46eaf1 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/CustomDatasourceRepositoryImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/CustomDatasourceRepositoryImpl.java @@ -1,9 +1,9 @@ package com.appsmith.server.repositories; +import com.appsmith.external.models.Datasource; import com.appsmith.external.models.DatasourceStructure; +import com.appsmith.external.models.QDatasource; import com.appsmith.server.acl.AclPermission; -import com.appsmith.server.domains.Datasource; -import com.appsmith.server.domains.QDatasource; import com.mongodb.client.result.UpdateResult; import org.springframework.data.mongodb.core.ReactiveMongoOperations; import org.springframework.data.mongodb.core.convert.MongoConverter; diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/DatasourceRepository.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/DatasourceRepository.java index fadbf4b60b..74f0e17a9c 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/DatasourceRepository.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/DatasourceRepository.java @@ -1,6 +1,6 @@ package com.appsmith.server.repositories; -import com.appsmith.server.domains.Datasource; +import com.appsmith.external.models.Datasource; import org.springframework.stereotype.Repository; import reactor.core.publisher.Flux; diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/AuthenticationValidator.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/AuthenticationValidator.java index 6dfc41ae3e..8d5fab7eb7 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/AuthenticationValidator.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/AuthenticationValidator.java @@ -2,7 +2,7 @@ package com.appsmith.server.services; import com.appsmith.external.models.AuthenticationDTO; import com.appsmith.external.models.OAuth2; -import com.appsmith.server.domains.Datasource; +import com.appsmith.external.models.Datasource; import com.appsmith.server.solutions.AuthenticationService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ConfigService.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ConfigService.java index e645fcb7f7..c79ea438ee 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ConfigService.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ConfigService.java @@ -2,7 +2,7 @@ package com.appsmith.server.services; import com.appsmith.server.domains.Application; import com.appsmith.server.domains.Config; -import com.appsmith.server.domains.Datasource; +import com.appsmith.external.models.Datasource; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ConfigServiceImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ConfigServiceImpl.java index 8ce0ad2066..0d9192eaaa 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ConfigServiceImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ConfigServiceImpl.java @@ -3,7 +3,7 @@ package com.appsmith.server.services; import com.appsmith.server.constants.FieldName; import com.appsmith.server.domains.Application; import com.appsmith.server.domains.Config; -import com.appsmith.server.domains.Datasource; +import com.appsmith.external.models.Datasource; import com.appsmith.server.exceptions.AppsmithError; import com.appsmith.server.exceptions.AppsmithException; import com.appsmith.server.repositories.ApplicationRepository; diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/CurlImporterService.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/CurlImporterService.java index 9f94525c01..b22795d415 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/CurlImporterService.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/CurlImporterService.java @@ -4,7 +4,7 @@ import com.appsmith.external.models.ActionConfiguration; import com.appsmith.external.models.DatasourceConfiguration; import com.appsmith.external.models.Property; import com.appsmith.server.constants.FieldName; -import com.appsmith.server.domains.Datasource; +import com.appsmith.external.models.Datasource; import com.appsmith.server.domains.Plugin; import com.appsmith.server.dtos.ActionDTO; import com.appsmith.server.exceptions.AppsmithError; diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/DatasourceContextService.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/DatasourceContextService.java index 98ce6ef748..290b2cb559 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/DatasourceContextService.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/DatasourceContextService.java @@ -1,6 +1,6 @@ package com.appsmith.server.services; -import com.appsmith.server.domains.Datasource; +import com.appsmith.external.models.Datasource; import com.appsmith.server.domains.DatasourceContext; import reactor.core.publisher.Mono; diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/DatasourceContextServiceImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/DatasourceContextServiceImpl.java index ad2724b376..d6a47e6e07 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/DatasourceContextServiceImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/DatasourceContextServiceImpl.java @@ -1,11 +1,10 @@ package com.appsmith.server.services; import com.appsmith.external.exceptions.pluginExceptions.StaleConnectionException; -import com.appsmith.external.models.AuthenticationDTO; import com.appsmith.external.models.UpdatableConnection; import com.appsmith.external.plugins.PluginExecutor; import com.appsmith.external.services.EncryptionService; -import com.appsmith.server.domains.Datasource; +import com.appsmith.external.models.Datasource; import com.appsmith.server.domains.DatasourceContext; import com.appsmith.server.domains.Plugin; import com.appsmith.server.helpers.PluginExecutorHelper; @@ -58,7 +57,7 @@ public class DatasourceContextServiceImpl implements DatasourceContextService { log.debug("This is a dry run or an embedded datasource. The datasource context would not exist in this scenario"); } else if (datasourceContextMap.get(datasourceId) != null - // The following condition happens when there's a timout in the middle of destroying a connection and + // The following condition happens when there's a timeout in the middle of destroying a connection and // the reactive flow interrupts, resulting in the destroy operation not completing. && datasourceContextMap.get(datasourceId).getConnection() != null && !isStale) { diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/DatasourceService.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/DatasourceService.java index f0d7369c31..0962a6d9b0 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/DatasourceService.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/DatasourceService.java @@ -2,7 +2,7 @@ package com.appsmith.server.services; import com.appsmith.external.models.DatasourceTestResult; import com.appsmith.server.acl.AclPermission; -import com.appsmith.server.domains.Datasource; +import com.appsmith.external.models.Datasource; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/DatasourceServiceImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/DatasourceServiceImpl.java index 0b31f379de..d67d57c3dd 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/DatasourceServiceImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/DatasourceServiceImpl.java @@ -10,7 +10,7 @@ import com.appsmith.external.plugins.PluginExecutor; import com.appsmith.server.acl.AclPermission; import com.appsmith.server.acl.PolicyGenerator; import com.appsmith.server.constants.FieldName; -import com.appsmith.server.domains.Datasource; +import com.appsmith.external.models.Datasource; import com.appsmith.server.domains.Organization; import com.appsmith.server.domains.Plugin; import com.appsmith.server.domains.User; diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ItemServiceImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ItemServiceImpl.java index bf10e292a9..b7a82dad12 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ItemServiceImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ItemServiceImpl.java @@ -2,7 +2,7 @@ package com.appsmith.server.services; import com.appsmith.external.models.ApiTemplate; import com.appsmith.server.constants.FieldName; -import com.appsmith.server.domains.Datasource; +import com.appsmith.external.models.Datasource; import com.appsmith.server.domains.Documentation; import com.appsmith.server.dtos.ActionDTO; import com.appsmith.server.dtos.AddItemToPageDTO; diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/LayoutActionServiceImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/LayoutActionServiceImpl.java index bc1666710a..30ccacffdd 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/LayoutActionServiceImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/LayoutActionServiceImpl.java @@ -8,7 +8,7 @@ import com.appsmith.external.models.DynamicBinding; import com.appsmith.server.constants.AnalyticsEvents; import com.appsmith.server.constants.FieldName; import com.appsmith.server.domains.ActionDependencyEdge; -import com.appsmith.server.domains.Datasource; +import com.appsmith.external.models.Datasource; import com.appsmith.server.domains.Layout; import com.appsmith.server.domains.NewAction; import com.appsmith.server.domains.NewPage; diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/MockDataService.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/MockDataService.java index 4e9eb640e2..99b31ec40f 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/MockDataService.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/MockDataService.java @@ -1,6 +1,6 @@ package com.appsmith.server.services; -import com.appsmith.server.domains.Datasource; +import com.appsmith.external.models.Datasource; import com.appsmith.server.dtos.MockDataDTO; import com.appsmith.server.dtos.MockDataSource; import reactor.core.publisher.Mono; diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/MockDataServiceImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/MockDataServiceImpl.java index 09eee1cb32..9b20c08def 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/MockDataServiceImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/MockDataServiceImpl.java @@ -8,7 +8,7 @@ import com.appsmith.external.models.Property; import com.appsmith.external.models.SSLDetails; import com.appsmith.server.configurations.CloudServicesConfig; import com.appsmith.server.constants.AnalyticsEvents; -import com.appsmith.server.domains.Datasource; +import com.appsmith.external.models.Datasource; import com.appsmith.server.domains.User; import com.appsmith.server.dtos.MockDataCredentials; import com.appsmith.server.dtos.MockDataDTO; @@ -28,10 +28,8 @@ import reactor.core.publisher.Mono; import java.time.Instant; import java.util.ArrayList; import java.util.List; -import java.util.Locale; import java.util.Map; import java.util.Optional; -import java.util.stream.Collectors; import static org.apache.commons.lang.ObjectUtils.defaultIfNull; diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/NewActionServiceImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/NewActionServiceImpl.java index 3dd019408f..1bc0118619 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/NewActionServiceImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/NewActionServiceImpl.java @@ -1,6 +1,8 @@ package com.appsmith.server.services; +import com.appsmith.external.dtos.DatasourceDTO; import com.appsmith.external.dtos.ExecuteActionDTO; +import com.appsmith.external.dtos.ExecutePluginDTO; import com.appsmith.external.exceptions.pluginExceptions.AppsmithPluginError; import com.appsmith.external.exceptions.pluginExceptions.AppsmithPluginException; import com.appsmith.external.exceptions.pluginExceptions.StaleConnectionException; @@ -8,6 +10,7 @@ import com.appsmith.external.helpers.MustacheHelper; import com.appsmith.external.models.ActionConfiguration; import com.appsmith.external.models.ActionExecutionRequest; import com.appsmith.external.models.ActionExecutionResult; +import com.appsmith.external.models.Datasource; import com.appsmith.external.models.Param; import com.appsmith.external.models.Policy; import com.appsmith.external.models.Provider; @@ -20,7 +23,7 @@ import com.appsmith.server.constants.FieldName; import com.appsmith.server.domains.Action; import com.appsmith.server.domains.ActionProvider; import com.appsmith.server.domains.Application; -import com.appsmith.server.domains.Datasource; +import com.appsmith.server.domains.DatasourceContext; import com.appsmith.server.domains.NewAction; import com.appsmith.server.domains.NewPage; import com.appsmith.server.domains.Page; @@ -98,6 +101,7 @@ public class NewActionServiceImpl extends BaseService pluginExecutorMono = pluginExecutorHelper.getPluginExecutor(pluginMono); @@ -543,12 +550,14 @@ public class NewActionServiceImpl extends BaseService { final ActionDTO action = tuple.getT1(); final Datasource datasource = tuple.getT2(); final PluginExecutor pluginExecutor = tuple.getT3(); + final Plugin plugin = tuple.getT4(); // Set the action name actionName.set(action.getName()); @@ -564,7 +573,13 @@ public class NewActionServiceImpl extends BaseService validatedDatasourceMono = authenticationValidator.validateAuthentication(datasource).cache(); Mono executionMono = validatedDatasourceMono - .flatMap(datasourceContextService::getDatasourceContext) + .flatMap(datasource1 -> { + if (plugin.isRemotePlugin()) { + return this.getRemoteDatasourceContext(plugin, datasource1); + } else { + return datasourceContextService.getDatasourceContext(datasource1); + } + }) // Now that we have the context (connection details), execute the action. .flatMap(resourceContext -> validatedDatasourceMono .flatMap(datasource1 -> { @@ -1035,6 +1050,23 @@ public class NewActionServiceImpl extends BaseService !PluginType.JS.equals(actionDTO.getPluginType())); } + // We can afford to make this call all the time since we already have all the info we need in context + private Mono getRemoteDatasourceContext(Plugin plugin, Datasource datasource) { + final DatasourceContext datasourceContext = new DatasourceContext(); + + return configService.getInstanceId() + .map(instanceId -> { + ExecutePluginDTO executePluginDTO = new ExecutePluginDTO(); + executePluginDTO.setInstallationKey(instanceId); + executePluginDTO.setPluginName(plugin.getPluginName()); + executePluginDTO.setPluginVersion(plugin.getVersion()); + executePluginDTO.setDatasource(new DatasourceDTO(datasource.getId(), datasource.getDatasourceConfiguration())); + datasourceContext.setConnection(executePluginDTO); + + return datasourceContext; + }); + } + @Override public Mono save(NewAction action) { // gitSyncId will be used to sync resource across instances diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/OrganizationService.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/OrganizationService.java index b2dfddc38e..da0af2c24c 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/OrganizationService.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/OrganizationService.java @@ -39,4 +39,6 @@ public interface OrganizationService extends CrudService { Mono uploadLogo(String organizationId, Part filePart); Mono deleteLogo(String organizationId); + + Flux getAll(); } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/OrganizationServiceImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/OrganizationServiceImpl.java index a78e050ef3..7cb93b18db 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/OrganizationServiceImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/OrganizationServiceImpl.java @@ -338,4 +338,9 @@ public class OrganizationServiceImpl extends BaseService getAll() { + return repository.findAll(); + } + } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/PluginService.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/PluginService.java index 0a93b3e713..117df20fd8 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/PluginService.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/PluginService.java @@ -1,6 +1,6 @@ package com.appsmith.server.services; -import com.appsmith.server.domains.Datasource; +import com.appsmith.external.models.Datasource; import com.appsmith.server.domains.Organization; import com.appsmith.server.domains.Plugin; import com.appsmith.server.dtos.InstallPluginRedisDTO; @@ -8,6 +8,7 @@ import com.appsmith.server.dtos.PluginOrgDTO; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; +import java.util.List; import java.util.Map; public interface PluginService extends CrudService { @@ -16,6 +17,8 @@ public interface PluginService extends CrudService { Mono installPlugin(PluginOrgDTO plugin); + Flux installDefaultPlugins(List plugins); + Mono uninstallPlugin(PluginOrgDTO plugin); Mono findByName(String name); @@ -30,9 +33,13 @@ public interface PluginService extends CrudService { Mono getFormConfig(String pluginId); + Flux getAllRemotePlugins(); + Mono loadPluginResource(String pluginId, String resourcePath); Mono getEditorConfigLabelMap(String pluginId); Map loadEditorPluginResourceUqi(Plugin plugin); + + Flux saveAll(Iterable plugins); } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/PluginServiceImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/PluginServiceImpl.java index e5e782fdd5..b06d986a95 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/PluginServiceImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/PluginServiceImpl.java @@ -1,7 +1,7 @@ package com.appsmith.server.services; +import com.appsmith.external.models.Datasource; import com.appsmith.server.constants.FieldName; -import com.appsmith.server.domains.Datasource; import com.appsmith.server.domains.Organization; import com.appsmith.server.domains.OrganizationPlugin; import com.appsmith.server.domains.Plugin; @@ -185,6 +185,22 @@ public class PluginServiceImpl extends BaseService installDefaultPlugins(List plugins) { + final List newOrganizationPlugins = plugins + .stream() + .filter(plugin -> Boolean.TRUE.equals(plugin.getDefaultInstall())) + .map(plugin -> { + return new OrganizationPlugin(plugin.getId(), OrganizationPluginStatus.ACTIVATED); + }) + .collect(Collectors.toList()); + return organizationService.getAll() + .flatMap(organization -> { + organization.getPlugins().addAll(newOrganizationPlugins); + return organizationService.save(organization); + }); + } + @Override public Mono uninstallPlugin(PluginOrgDTO pluginDTO) { if (pluginDTO.getPluginId() == null) { @@ -626,6 +642,16 @@ public class PluginServiceImpl extends BaseService saveAll(Iterable plugins) { + return repository.saveAll(plugins); + } + + @Override + public Flux getAllRemotePlugins() { + return repository.findByType(PluginType.REMOTE); + } + private Map loadPluginResourceGivenPlugin(Plugin plugin, String resourcePath) { InputStream resourceAsStream = pluginManager .getPlugin(plugin.getPackageName()) @@ -649,8 +675,21 @@ public class PluginServiceImpl extends BaseService loadPluginResource(String pluginId, String resourcePath) { return findById(pluginId) .map(plugin -> { - if (resourcePath.equals("editor.json") && plugin.getUiComponent().equals(UQI_DB_EDITOR_FORM)) { - return loadEditorPluginResourceUqi(plugin); + if ("editor.json".equals(resourcePath)) { + // UI config will be available if this plugin is sourced from the cloud + if (plugin.getActionUiConfig() != null) { + return plugin.getActionUiConfig(); + } + // For UQI, use another format of loading the config + if (UQI_DB_EDITOR_FORM.equals(plugin.getUiComponent())) { + return loadEditorPluginResourceUqi(plugin); + } + } + if ("form.json".equals(resourcePath)) { + // UI config will be available if this plugin is sourced from the cloud + if (plugin.getDatasourceUiConfig() != null) { + return plugin.getDatasourceUiConfig(); + } } return loadPluginResourceGivenPlugin(plugin, resourcePath); }); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/PostmanImporterService.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/PostmanImporterService.java index ee4b7835f5..f8a0a2eb8f 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/PostmanImporterService.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/PostmanImporterService.java @@ -5,7 +5,7 @@ import com.appsmith.external.models.ApiTemplate; import com.appsmith.external.models.DatasourceConfiguration; import com.appsmith.external.models.Property; import com.appsmith.external.models.TemplateCollection; -import com.appsmith.server.domains.Datasource; +import com.appsmith.external.models.Datasource; import com.appsmith.server.dtos.ActionDTO; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpMethod; diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/UserOrganizationServiceImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/UserOrganizationServiceImpl.java index e204f876e9..4dad96f685 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/UserOrganizationServiceImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/UserOrganizationServiceImpl.java @@ -8,7 +8,7 @@ import com.appsmith.server.domains.Action; import com.appsmith.server.domains.ActionCollection; import com.appsmith.server.domains.Application; import com.appsmith.server.domains.CommentThread; -import com.appsmith.server.domains.Datasource; +import com.appsmith.external.models.Datasource; import com.appsmith.server.domains.NewAction; import com.appsmith.server.domains.NewPage; import com.appsmith.server.domains.Organization; diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/AuthenticationService.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/AuthenticationService.java index 98bec22936..b10fb84b6c 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/AuthenticationService.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/AuthenticationService.java @@ -11,7 +11,7 @@ import com.appsmith.server.configurations.CloudServicesConfig; import com.appsmith.server.constants.Entity; import com.appsmith.server.constants.FieldName; import com.appsmith.server.constants.Url; -import com.appsmith.server.domains.Datasource; +import com.appsmith.external.models.Datasource; import com.appsmith.server.domains.Plugin; import com.appsmith.server.domains.PluginType; import com.appsmith.server.dtos.AuthorizationCodeCallbackDTO; diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/CreateDBTablePageSolution.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/CreateDBTablePageSolution.java index 1b498dee1a..8ab02920e8 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/CreateDBTablePageSolution.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/CreateDBTablePageSolution.java @@ -13,7 +13,7 @@ import com.appsmith.server.constants.Entity; import com.appsmith.server.constants.FieldName; import com.appsmith.server.constants.Resources; import com.appsmith.server.domains.ApplicationJson; -import com.appsmith.server.domains.Datasource; +import com.appsmith.external.models.Datasource; import com.appsmith.server.domains.Layout; import com.appsmith.server.domains.NewAction; import com.appsmith.server.domains.NewPage; diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/DatasourceStructureSolution.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/DatasourceStructureSolution.java index 321a984a4c..7f630ecf05 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/DatasourceStructureSolution.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/DatasourceStructureSolution.java @@ -10,7 +10,7 @@ import com.appsmith.external.models.Property; import com.appsmith.external.plugins.PluginExecutor; import com.appsmith.server.acl.AclPermission; import com.appsmith.server.constants.FieldName; -import com.appsmith.server.domains.Datasource; +import com.appsmith.external.models.Datasource; import com.appsmith.server.exceptions.AppsmithError; import com.appsmith.server.exceptions.AppsmithException; import com.appsmith.server.helpers.PluginExecutorHelper; diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ExamplesOrganizationCloner.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ExamplesOrganizationCloner.java index ecce5de8d7..117d522300 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ExamplesOrganizationCloner.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ExamplesOrganizationCloner.java @@ -7,7 +7,7 @@ import com.appsmith.external.models.BaseDomain; import com.appsmith.server.constants.FieldName; import com.appsmith.server.domains.Application; import com.appsmith.server.domains.ApplicationPage; -import com.appsmith.server.domains.Datasource; +import com.appsmith.external.models.Datasource; import com.appsmith.server.domains.Layout; import com.appsmith.server.domains.NewPage; import com.appsmith.server.domains.Organization; diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ImportExportApplicationService.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ImportExportApplicationService.java index c1211c4c1e..020b34a6e7 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ImportExportApplicationService.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ImportExportApplicationService.java @@ -15,7 +15,7 @@ import com.appsmith.server.constants.SerialiseApplicationObjective; import com.appsmith.server.domains.Application; import com.appsmith.server.domains.ApplicationJson; import com.appsmith.server.domains.ApplicationPage; -import com.appsmith.server.domains.Datasource; +import com.appsmith.external.models.Datasource; import com.appsmith.server.domains.NewAction; import com.appsmith.server.domains.NewPage; import com.appsmith.server.domains.PluginType; diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/PluginScheduledTask.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/PluginScheduledTask.java new file mode 100644 index 0000000000..279da4ce17 --- /dev/null +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/PluginScheduledTask.java @@ -0,0 +1,127 @@ +package com.appsmith.server.solutions; + +import com.appsmith.server.configurations.CloudServicesConfig; +import com.appsmith.server.domains.Organization; +import com.appsmith.server.domains.Plugin; +import com.appsmith.server.dtos.ResponseDTO; +import com.appsmith.server.services.ConfigService; +import com.appsmith.server.services.PluginService; +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; +import org.springframework.web.reactive.function.client.WebClient; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import reactor.core.scheduler.Schedulers; + +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * This class represents a scheduled task that pings cloud services for any updates in available plugins. + */ +@Component +@Slf4j +@RequiredArgsConstructor +public class PluginScheduledTask { + + private final ConfigService configService; + private final PluginService pluginService; + private final CloudServicesConfig cloudServicesConfig; + + private Instant lastUpdatedAt = null; + + /** + * Gets the external IP address of this server and pings a data point to indicate that this server instance is live. + * We use an initial delay of two minutes to roughly wait for the application along with the migrations are finished + * and ready. + */ + // Number of milliseconds between the start of each scheduled calls to this method. + @Scheduled(initialDelay = 2 * 60 * 1000 /* two minutes */, fixedRate = 2 * 60 * 60 * 1000 /* two hours */) + public void updateRemotePlugins() { + // Get all plugins on this instance + final Mono> availablePluginsMono = + pluginService + .getAllRemotePlugins() + .collect(Collectors.toMap( + plugin -> new PluginIdentifier(plugin.getPluginName(), plugin.getVersion()), + plugin -> plugin + )); + + final Mono> newPluginsMono = getRemotePlugins(); + + Mono.zip(availablePluginsMono, newPluginsMono) + .flatMapMany(tuple -> { + final Map availablePlugins = tuple.getT1(); + final Map newPlugins = tuple.getT2(); + final List updatablePlugins = new ArrayList<>(); + final List insertablePlugins = new ArrayList<>(); + newPlugins.forEach((k, v) -> { + if (availablePlugins.containsKey(k)) { + v.setId(availablePlugins.get(k).getId()); + updatablePlugins.add(v); + } else { + insertablePlugins.add(v); + } + }); + + final Flux updatedPluginsFlux = pluginService.saveAll(updatablePlugins); + final Flux organizationFlux = pluginService.saveAll(insertablePlugins) + .filter(Plugin::getDefaultInstall) + .collectList() + .flatMapMany(pluginService::installDefaultPlugins); + + return updatedPluginsFlux.zipWith(organizationFlux); + }) + .subscribeOn(Schedulers.single()) + .subscribe(); + } + + private Mono> getRemotePlugins() { + + final String baseUrl = cloudServicesConfig.getBaseUrl(); + if (StringUtils.isEmpty(baseUrl)) { + return Mono.empty(); + } + + return configService.getInstanceId() + .flatMap(instanceId -> WebClient + .create( + baseUrl + "/api/v1/plugins?instanceId=" + instanceId + + "&lastUpdatedAt=" + lastUpdatedAt) + .get() + .exchange() + .flatMap(response -> response.bodyToMono(new ParameterizedTypeReference>>() { + })) + .map(ResponseDTO::getData) + .map(plugins -> { + // Set new updated time + this.lastUpdatedAt = Instant.now(); + + // Parse plugins into map for easier manipulation + return plugins + .stream() + .collect(Collectors.toMap( + plugin -> new PluginIdentifier(plugin.getPluginName(), plugin.getVersion()), + plugin -> plugin + )); + })); + } + + @AllArgsConstructor + @Getter + @EqualsAndHashCode + private static class PluginIdentifier { + String pluginName; + String version; + } +} diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ActionCollectionServiceTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ActionCollectionServiceTest.java index 7f7c483b0a..71c99bf69d 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ActionCollectionServiceTest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ActionCollectionServiceTest.java @@ -6,7 +6,7 @@ import com.appsmith.server.acl.AclPermission; import com.appsmith.server.acl.AppsmithRole; import com.appsmith.server.domains.ActionCollection; import com.appsmith.server.domains.Application; -import com.appsmith.server.domains.Datasource; +import com.appsmith.external.models.Datasource; import com.appsmith.server.domains.Layout; import com.appsmith.server.domains.NewAction; import com.appsmith.server.domains.Organization; diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ActionServiceTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ActionServiceTest.java index aafffb7cc4..9340247dbf 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ActionServiceTest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ActionServiceTest.java @@ -9,6 +9,7 @@ import com.appsmith.external.helpers.AppsmithEventContext; import com.appsmith.external.helpers.AppsmithEventContextType; import com.appsmith.external.models.ActionConfiguration; import com.appsmith.external.models.ActionExecutionResult; +import com.appsmith.external.models.Datasource; import com.appsmith.external.models.DatasourceConfiguration; import com.appsmith.external.models.PaginationField; import com.appsmith.external.models.PaginationType; @@ -21,7 +22,6 @@ import com.appsmith.external.plugins.PluginExecutor; import com.appsmith.server.acl.AclPermission; import com.appsmith.server.constants.FieldName; import com.appsmith.server.domains.Application; -import com.appsmith.server.domains.Datasource; import com.appsmith.server.domains.Layout; import com.appsmith.server.domains.NewAction; import com.appsmith.server.domains.Organization; @@ -187,6 +187,7 @@ public class ActionServiceTest { datasource.setOrganizationId(orgId); Plugin installed_plugin = pluginRepository.findByPackageName("installed-plugin").block(); datasource.setPluginId(installed_plugin.getId()); + datasource.setDatasourceConfiguration(new DatasourceConfiguration()); } @After diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ApplicationServiceTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ApplicationServiceTest.java index 9cf90502d7..b4527a178e 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ApplicationServiceTest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ApplicationServiceTest.java @@ -7,7 +7,7 @@ import com.appsmith.server.acl.AclPermission; import com.appsmith.server.constants.FieldName; import com.appsmith.server.domains.Application; import com.appsmith.server.domains.ApplicationPage; -import com.appsmith.server.domains.Datasource; +import com.appsmith.external.models.Datasource; import com.appsmith.server.domains.GitApplicationMetadata; import com.appsmith.server.domains.GitAuth; import com.appsmith.server.domains.Layout; diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/DatasourceContextServiceTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/DatasourceContextServiceTest.java index 6f7ca33aed..db740fb4d6 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/DatasourceContextServiceTest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/DatasourceContextServiceTest.java @@ -4,7 +4,7 @@ import com.appsmith.external.models.DBAuth; import com.appsmith.external.models.DatasourceConfiguration; import com.appsmith.external.services.EncryptionService; import com.appsmith.server.acl.AclPermission; -import com.appsmith.server.domains.Datasource; +import com.appsmith.external.models.Datasource; import com.appsmith.server.domains.Organization; import com.appsmith.server.domains.Plugin; import com.appsmith.server.helpers.MockPluginExecutor; diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/DatasourceServiceTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/DatasourceServiceTest.java index 02e688182c..108bd15337 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/DatasourceServiceTest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/DatasourceServiceTest.java @@ -14,7 +14,7 @@ import com.appsmith.external.services.EncryptionService; import com.appsmith.server.acl.AclPermission; import com.appsmith.server.constants.FieldName; import com.appsmith.server.domains.Application; -import com.appsmith.server.domains.Datasource; +import com.appsmith.external.models.Datasource; import com.appsmith.server.domains.Organization; import com.appsmith.server.domains.Plugin; import com.appsmith.server.dtos.ActionDTO; diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/LayoutActionServiceTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/LayoutActionServiceTest.java index 06b8f8f6d8..4deacb0aef 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/LayoutActionServiceTest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/LayoutActionServiceTest.java @@ -5,7 +5,7 @@ import com.appsmith.external.models.DatasourceConfiguration; import com.appsmith.server.acl.AclPermission; import com.appsmith.server.constants.FieldName; import com.appsmith.server.domains.Application; -import com.appsmith.server.domains.Datasource; +import com.appsmith.external.models.Datasource; import com.appsmith.server.domains.Layout; import com.appsmith.server.domains.NewAction; import com.appsmith.server.domains.Organization; diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/LayoutServiceTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/LayoutServiceTest.java index c8ec6e6e73..008d52a90f 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/LayoutServiceTest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/LayoutServiceTest.java @@ -4,7 +4,7 @@ import com.appsmith.external.models.ActionConfiguration; import com.appsmith.server.acl.AclPermission; import com.appsmith.server.constants.FieldName; import com.appsmith.server.domains.Application; -import com.appsmith.server.domains.Datasource; +import com.appsmith.external.models.Datasource; import com.appsmith.server.domains.Layout; import com.appsmith.server.domains.Plugin; import com.appsmith.server.domains.PluginType; diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/MockDataServiceTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/MockDataServiceTest.java index e8f9634df1..c90e5f67e8 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/MockDataServiceTest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/MockDataServiceTest.java @@ -7,7 +7,7 @@ import com.appsmith.external.models.DBAuth; import com.appsmith.external.models.Policy; import com.appsmith.server.acl.AclPermission; import com.appsmith.server.domains.Application; -import com.appsmith.server.domains.Datasource; +import com.appsmith.external.models.Datasource; import com.appsmith.server.domains.Organization; import com.appsmith.server.domains.Plugin; import com.appsmith.server.domains.User; diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/OrganizationServiceTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/OrganizationServiceTest.java index 3fa53d183d..0ed25aeceb 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/OrganizationServiceTest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/OrganizationServiceTest.java @@ -9,7 +9,7 @@ import com.appsmith.server.constants.Constraint; import com.appsmith.server.constants.FieldName; import com.appsmith.server.domains.Application; import com.appsmith.server.domains.Asset; -import com.appsmith.server.domains.Datasource; +import com.appsmith.external.models.Datasource; import com.appsmith.server.domains.Organization; import com.appsmith.server.domains.User; import com.appsmith.server.domains.UserRole; diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/PageServiceTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/PageServiceTest.java index a8025d053a..34a250b6fa 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/PageServiceTest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/PageServiceTest.java @@ -5,7 +5,7 @@ import com.appsmith.external.models.Policy; import com.appsmith.external.plugins.PluginExecutor; import com.appsmith.server.constants.FieldName; import com.appsmith.server.domains.Application; -import com.appsmith.server.domains.Datasource; +import com.appsmith.external.models.Datasource; import com.appsmith.server.domains.Layout; import com.appsmith.server.domains.NewAction; import com.appsmith.server.domains.Plugin; diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/ApplicationForkingServiceTests.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/ApplicationForkingServiceTests.java index 6fc27c4e0e..953c26504b 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/ApplicationForkingServiceTests.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/ApplicationForkingServiceTests.java @@ -2,7 +2,7 @@ package com.appsmith.server.solutions; import com.appsmith.server.constants.FieldName; import com.appsmith.server.domains.Application; -import com.appsmith.server.domains.Datasource; +import com.appsmith.external.models.Datasource; import com.appsmith.server.domains.Organization; import com.appsmith.server.dtos.ActionDTO; import com.appsmith.server.helpers.MockPluginExecutor; diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/AuthenticationServiceTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/AuthenticationServiceTest.java index 5397995f22..eaca1efc50 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/AuthenticationServiceTest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/AuthenticationServiceTest.java @@ -6,7 +6,7 @@ import com.appsmith.external.models.OAuth2; import com.appsmith.external.models.Property; import com.appsmith.server.acl.AclPermission; import com.appsmith.server.domains.Application; -import com.appsmith.server.domains.Datasource; +import com.appsmith.external.models.Datasource; import com.appsmith.server.domains.Organization; import com.appsmith.server.domains.Plugin; import com.appsmith.server.domains.User; diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/CreateDBTablePageSolutionTests.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/CreateDBTablePageSolutionTests.java index d2b6d9bfd2..a7df1e5a88 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/CreateDBTablePageSolutionTests.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/CreateDBTablePageSolutionTests.java @@ -10,7 +10,7 @@ import com.appsmith.external.models.DatasourceStructure.TableType; import com.appsmith.external.models.Property; import com.appsmith.server.constants.FieldName; import com.appsmith.server.domains.Application; -import com.appsmith.server.domains.Datasource; +import com.appsmith.external.models.Datasource; import com.appsmith.server.domains.Layout; import com.appsmith.server.domains.NewAction; import com.appsmith.server.domains.Organization; diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/ExamplesOrganizationClonerTests.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/ExamplesOrganizationClonerTests.java index f4d7fb3b3d..a6e9d10959 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/ExamplesOrganizationClonerTests.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/ExamplesOrganizationClonerTests.java @@ -14,7 +14,7 @@ import com.appsmith.external.models.UploadedFile; import com.appsmith.server.constants.FieldName; import com.appsmith.server.domains.Application; import com.appsmith.server.domains.ApplicationPage; -import com.appsmith.server.domains.Datasource; +import com.appsmith.external.models.Datasource; import com.appsmith.server.domains.Layout; import com.appsmith.server.domains.NewAction; import com.appsmith.server.domains.NewPage; diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/ImportExportApplicationServiceTests.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/ImportExportApplicationServiceTests.java index 7979156b4d..0da293aebf 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/ImportExportApplicationServiceTests.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/ImportExportApplicationServiceTests.java @@ -11,7 +11,7 @@ import com.appsmith.server.constants.SerialiseApplicationObjective; import com.appsmith.server.domains.Application; import com.appsmith.server.domains.ApplicationJson; import com.appsmith.server.domains.ApplicationPage; -import com.appsmith.server.domains.Datasource; +import com.appsmith.external.models.Datasource; import com.appsmith.server.domains.GitApplicationMetadata; import com.appsmith.server.domains.Layout; import com.appsmith.server.domains.NewAction; diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/ShareOrganizationPermissionTests.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/ShareOrganizationPermissionTests.java index bcb0f1d972..9717f1637b 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/ShareOrganizationPermissionTests.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/ShareOrganizationPermissionTests.java @@ -5,7 +5,7 @@ import com.appsmith.external.models.DatasourceConfiguration; import com.appsmith.external.models.Policy; import com.appsmith.server.acl.AppsmithRole; import com.appsmith.server.domains.Application; -import com.appsmith.server.domains.Datasource; +import com.appsmith.external.models.Datasource; import com.appsmith.server.domains.NewAction; import com.appsmith.server.domains.Organization; import com.appsmith.server.domains.Plugin; diff --git a/app/server/build.sh b/app/server/build.sh index ae7314937d..aeff8df783 100755 --- a/app/server/build.sh +++ b/app/server/build.sh @@ -8,7 +8,7 @@ mvn clean package "$@" if [ $? -eq 0 ] then - echo "mvn Successfull" + echo "mvn Successful" else echo "mvn Failed" exit 1