feat: Introducing SaaS integrations as a plugin (#7560)
* WIP client side changes * Saas execution flow + scheduled import of remote plugins
This commit is contained in:
parent
b26fc9965a
commit
c3f4cdaa15
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -104,6 +104,7 @@ function Command(props: {
|
|||
DB: <DataSourcesColoredIcon />,
|
||||
API: <ApisIcon />,
|
||||
SAAS: <DataSourcesColoredIcon />,
|
||||
REMOTE: <DataSourcesColoredIcon />,
|
||||
JS: <JsIcon />,
|
||||
}[props.pluginType]}
|
||||
{props.imgSrc && <img src={props.imgSrc} />}
|
||||
|
|
|
|||
|
|
@ -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 };
|
||||
|
|
|
|||
|
|
@ -119,6 +119,7 @@ export const defaultActionSettings: Record<PluginType, any> = {
|
|||
[PluginType.API]: apiActionSettingsConfig,
|
||||
[PluginType.DB]: queryActionSettingsConfig,
|
||||
[PluginType.SAAS]: saasActionSettingsConfig,
|
||||
[PluginType.REMOTE]: saasActionSettingsConfig,
|
||||
[PluginType.JS]: [],
|
||||
};
|
||||
|
||||
|
|
@ -126,6 +127,7 @@ export const defaultActionEditorConfigs: Record<PluginType, any> = {
|
|||
[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]: {},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ export type ActionGroupConfig = {
|
|||
export const ACTION_PLUGIN_MAP: Array<ActionGroupConfig | undefined> = [
|
||||
{
|
||||
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<ActionGroupConfig | undefined> = [
|
|||
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;
|
||||
|
||||
|
|
|
|||
|
|
@ -294,7 +294,9 @@ function NewApiScreen(props: Props) {
|
|||
</ApiCard>
|
||||
)}
|
||||
{plugins
|
||||
.filter((p) => p.type === PluginType.SAAS)
|
||||
.filter(
|
||||
(p) => p.type === PluginType.SAAS || p.type === PluginType.REMOTE,
|
||||
)
|
||||
.map((p) => (
|
||||
<ApiCard
|
||||
className={`t--createBlankApi-${p.packageName}`}
|
||||
|
|
|
|||
|
|
@ -20,9 +20,9 @@ import {
|
|||
getPluginIdsOfPackageNames,
|
||||
getPlugins,
|
||||
getPluginImages,
|
||||
getDBDatasources,
|
||||
getAction,
|
||||
getActionResponses,
|
||||
getDBAndRemoteDatasources,
|
||||
} from "selectors/entitiesSelector";
|
||||
import { PLUGIN_PACKAGE_DBS } from "constants/QueryEditorConstants";
|
||||
import { QueryAction, QueryActionConfig } from "entities/Action";
|
||||
|
|
@ -248,7 +248,7 @@ const mapStateToProps = (state: AppState, props: any): ReduxStateProps => {
|
|||
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],
|
||||
|
|
|
|||
|
|
@ -160,7 +160,7 @@ function* handleQueryCreatedSaga(actionPayload: ReduxAction<QueryAction>) {
|
|||
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<QueryAction>) {
|
|||
|
||||
function* handleDatasourceCreatedSaga(actionPayload: ReduxAction<Datasource>) {
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -131,6 +131,10 @@
|
|||
<artifactId>h2</artifactId>
|
||||
<version>1.4.200</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-webflux</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
</dependencies>
|
||||
|
|
|
|||
14
app/server/appsmith-interfaces/src/main/java/com/appsmith/external/dtos/DatasourceDTO.java
vendored
Normal file
14
app/server/appsmith-interfaces/src/main/java/com/appsmith/external/dtos/DatasourceDTO.java
vendored
Normal file
|
|
@ -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;
|
||||
}
|
||||
18
app/server/appsmith-interfaces/src/main/java/com/appsmith/external/dtos/ExecutePluginDTO.java
vendored
Normal file
18
app/server/appsmith-interfaces/src/main/java/com/appsmith/external/dtos/ExecutePluginDTO.java
vendored
Normal file
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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<String, Object> formData;
|
||||
|
||||
@Transient
|
||||
String templateName;
|
||||
|
||||
public void setTimeoutInMillisecond(String timeoutInMillisecond) {
|
||||
try {
|
||||
this.timeoutInMillisecond = Integer.valueOf(timeoutInMillisecond);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -5,4 +5,6 @@ public interface SharedConfig {
|
|||
int getCodecSize();
|
||||
|
||||
int getMaxResponseSize();
|
||||
|
||||
String getRemoteExecutionUrl();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,5 +30,6 @@
|
|||
<module>snowflakePlugin</module>
|
||||
<module>arangoDBPlugin</module>
|
||||
<module>jsPlugin</module>
|
||||
<module>saasPlugin</module>
|
||||
</modules>
|
||||
</project>
|
||||
|
|
@ -65,6 +65,11 @@ public class PostgresPluginTest {
|
|||
public int getMaxResponseSize() {
|
||||
return 10000;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRemoteExecutionUrl() {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
5
app/server/appsmith-plugins/saasPlugin/plugin.properties
Normal file
5
app/server/appsmith-plugins/saasPlugin/plugin.properties
Normal file
|
|
@ -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=
|
||||
120
app/server/appsmith-plugins/saasPlugin/pom.xml
Normal file
120
app/server/appsmith-plugins/saasPlugin/pom.xml
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.external.plugins</groupId>
|
||||
<artifactId>saasPlugin</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
|
||||
<name>saasPlugin</name>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<java.version>11</java.version>
|
||||
<maven.compiler.source>${java.version}</maven.compiler.source>
|
||||
<maven.compiler.target>${java.version}</maven.compiler.target>
|
||||
<plugin.id>saas-plugin</plugin.id>
|
||||
<plugin.class>com.external.plugins.SaasPlugin</plugin.class>
|
||||
<plugin.version>1.0-SNAPSHOT</plugin.version>
|
||||
<plugin.provider>tech@appsmith.com</plugin.provider>
|
||||
<plugin.dependencies/>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.pf4j</groupId>
|
||||
<artifactId>pf4j-spring</artifactId>
|
||||
<version>0.7.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.appsmith</groupId>
|
||||
<artifactId>interfaces</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
<version>5.2.3.RELEASE</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-web</artifactId>
|
||||
<version>5.2.3.RELEASE</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-webflux</artifactId>
|
||||
<version>5.2.3.RELEASE</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>io.projectreactor</groupId>
|
||||
<artifactId>reactor-core</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-web</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.2.4</version>
|
||||
<configuration>
|
||||
<minimizeJar>false</minimizeJar>
|
||||
<transformers>
|
||||
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
|
||||
<manifestEntries>
|
||||
<Plugin-Id>${plugin.id}</Plugin-Id>
|
||||
<Plugin-Class>${plugin.class}</Plugin-Class>
|
||||
<Plugin-Version>${plugin.version}</Plugin-Version>
|
||||
<Plugin-Provider>${plugin.provider}</Plugin-Provider>
|
||||
</manifestEntries>
|
||||
</transformer>
|
||||
</transformers>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
228
app/server/appsmith-plugins/saasPlugin/src/main/java/com/external/helpers/BodyReceiver.java
vendored
Normal file
228
app/server/appsmith-plugins/saasPlugin/src/main/java/com/external/helpers/BodyReceiver.java
vendored
Normal file
|
|
@ -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<Object> reference = new AtomicReference<>(DUMMY);
|
||||
|
||||
public Object receiveValue(BodyInserter<?, ? extends ReactiveHttpOutputMessage> bodyInserter) {
|
||||
demandValueFrom(bodyInserter);
|
||||
|
||||
return receivedValue();
|
||||
}
|
||||
|
||||
private void demandValueFrom(BodyInserter<?, ? extends ReactiveHttpOutputMessage> bodyInserter) {
|
||||
final BodyInserter<Object, MinimalHttpOutputMessage> inserter =
|
||||
(BodyInserter<Object, MinimalHttpOutputMessage>) 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<T> implements HttpMessageWriter<T> {
|
||||
|
||||
private final Consumer<T> consumer;
|
||||
private final List<MediaType> mediaTypes;
|
||||
|
||||
WriteToConsumer(Consumer<T> consumer) {
|
||||
this.consumer = consumer;
|
||||
this.mediaTypes = Collections.singletonList(MediaType.ALL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MediaType> getWritableMediaTypes() {
|
||||
return mediaTypes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canWrite(ResolvableType elementType, MediaType mediaType) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> write(
|
||||
Publisher<? extends T> inputStream,
|
||||
ResolvableType elementType,
|
||||
MediaType mediaType,
|
||||
ReactiveHttpOutputMessage message,
|
||||
Map<String, Object> 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<? extends Mono<Void>> action) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCommitted() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> writeAndFlushWith(Publisher<? extends Publisher<? extends DataBuffer>> body) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> setComplete() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpMethod getMethod() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI getURI() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MultiValueMap<String, HttpCookie> getCookies() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static class OneValueConsumption<T> implements Subscriber<T> {
|
||||
|
||||
private final Consumer<T> consumer;
|
||||
private int remainedAccepts;
|
||||
|
||||
public OneValueConsumption(Consumer<T> 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<HttpMessageWriter<?>> singleWriterList;
|
||||
|
||||
SingleWriterContext(HttpMessageWriter<?> writer) {
|
||||
this.singleWriterList = List.of(writer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<HttpMessageWriter<?>> messageWriters() {
|
||||
return singleWriterList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<ServerHttpRequest> serverRequest() {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> hints() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
147
app/server/appsmith-plugins/saasPlugin/src/main/java/com/external/helpers/RequestCaptureFilter.java
vendored
Normal file
147
app/server/appsmith-plugins/saasPlugin/src/main/java/com/external/helpers/RequestCaptureFilter.java
vendored
Normal file
|
|
@ -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<ClientResponse> 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<String, String> 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<Map.Entry<String, String>> insertedParams,
|
||||
ObjectMapper objectMapper) {
|
||||
|
||||
ActionExecutionRequest actionExecutionRequest = new ActionExecutionRequest();
|
||||
|
||||
if (!insertedParams.isEmpty()) {
|
||||
final Map<String, Object> requestData = new HashMap<>();
|
||||
requestData.put("smart-substitution-parameters", insertedParams);
|
||||
actionExecutionRequest.setProperties(requestData);
|
||||
}
|
||||
|
||||
AtomicReference<String> reqContentType = new AtomicReference<>();
|
||||
|
||||
if (actionConfiguration.getHeaders() != null) {
|
||||
MultiValueMap<String, String> 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<Property> bodyFormData = actionConfiguration.getBodyFormData();
|
||||
Map<String, Object> 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<Property> bodyFormData = actionConfiguration.getBodyFormData();
|
||||
Map<String, Object> bodyDataMap = new HashMap<>();
|
||||
bodyFormData.forEach(property -> {
|
||||
if ("FILE".equalsIgnoreCase(property.getType())) {
|
||||
bodyDataMap.put(property.getKey(), "<file>");
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
219
app/server/appsmith-plugins/saasPlugin/src/main/java/com/external/plugins/SaasPlugin.java
vendored
Normal file
219
app/server/appsmith-plugins/saasPlugin/src/main/java/com/external/plugins/SaasPlugin.java
vendored
Normal file
|
|
@ -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<ExecutePluginDTO>, 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<ActionExecutionResult> 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<ClientResponse> 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<?, ? super ClientHttpRequest>) 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<ExecutePluginDTO> datasourceCreate(DatasourceConfiguration datasourceConfiguration) {
|
||||
return Mono.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void datasourceDestroy(ExecutePluginDTO connection) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> validateDatasource(DatasourceConfiguration datasourceConfiguration) {
|
||||
return Set.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<DatasourceTestResult> testDatasource(DatasourceConfiguration datasourceConfiguration) {
|
||||
return Mono.empty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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<String, String> templates;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
package com.appsmith.server.domains;
|
||||
|
||||
public enum PluginType {
|
||||
DB, API, JS, SAAS
|
||||
DB, API, JS, SAAS, REMOTE
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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<NewActionRepository, NewAc
|
|||
private final PolicyUtils policyUtils;
|
||||
private final ObjectMapper objectMapper;
|
||||
private final AuthenticationValidator authenticationValidator;
|
||||
private final ConfigService configService;
|
||||
|
||||
public NewActionServiceImpl(Scheduler scheduler,
|
||||
Validator validator,
|
||||
|
|
@ -115,7 +119,8 @@ public class NewActionServiceImpl extends BaseService<NewActionRepository, NewAc
|
|||
ApplicationService applicationService,
|
||||
SessionUserService sessionUserService,
|
||||
PolicyUtils policyUtils,
|
||||
AuthenticationValidator authenticationValidator) {
|
||||
AuthenticationValidator authenticationValidator,
|
||||
ConfigService configService) {
|
||||
super(scheduler, validator, mongoConverter, reactiveMongoTemplate, repository, analyticsService);
|
||||
this.repository = repository;
|
||||
this.datasourceService = datasourceService;
|
||||
|
|
@ -129,6 +134,7 @@ public class NewActionServiceImpl extends BaseService<NewActionRepository, NewAc
|
|||
this.sessionUserService = sessionUserService;
|
||||
this.policyUtils = policyUtils;
|
||||
this.authenticationValidator = authenticationValidator;
|
||||
this.configService = configService;
|
||||
this.objectMapper = new ObjectMapper();
|
||||
}
|
||||
|
||||
|
|
@ -534,7 +540,8 @@ public class NewActionServiceImpl extends BaseService<NewActionRepository, NewAc
|
|||
}
|
||||
return pluginService.findById(datasource.getPluginId());
|
||||
})
|
||||
.switchIfEmpty(Mono.error(new AppsmithException(AppsmithError.NO_RESOURCE_FOUND, FieldName.PLUGIN)));
|
||||
.switchIfEmpty(Mono.error(new AppsmithException(AppsmithError.NO_RESOURCE_FOUND, FieldName.PLUGIN)))
|
||||
.cache();
|
||||
|
||||
Mono<PluginExecutor> pluginExecutorMono = pluginExecutorHelper.getPluginExecutor(pluginMono);
|
||||
|
||||
|
|
@ -543,12 +550,14 @@ public class NewActionServiceImpl extends BaseService<NewActionRepository, NewAc
|
|||
.zip(
|
||||
actionDTOMono,
|
||||
datasourceMono,
|
||||
pluginExecutorMono
|
||||
pluginExecutorMono,
|
||||
pluginMono
|
||||
)
|
||||
.flatMap(tuple -> {
|
||||
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<NewActionRepository, NewAc
|
|||
Mono<Datasource> validatedDatasourceMono = authenticationValidator.validateAuthentication(datasource).cache();
|
||||
|
||||
Mono<ActionExecutionResult> 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<NewActionRepository, NewAc
|
|||
.filter(actionDTO -> !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<DatasourceContext> 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<NewAction> save(NewAction action) {
|
||||
// gitSyncId will be used to sync resource across instances
|
||||
|
|
|
|||
|
|
@ -39,4 +39,6 @@ public interface OrganizationService extends CrudService<Organization, String> {
|
|||
Mono<Organization> uploadLogo(String organizationId, Part filePart);
|
||||
|
||||
Mono<Organization> deleteLogo(String organizationId);
|
||||
|
||||
Flux<Organization> getAll();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -338,4 +338,9 @@ public class OrganizationServiceImpl extends BaseService<OrganizationRepository,
|
|||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<Organization> getAll() {
|
||||
return repository.findAll();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Plugin, String> {
|
||||
|
|
@ -16,6 +17,8 @@ public interface PluginService extends CrudService<Plugin, String> {
|
|||
|
||||
Mono<Organization> installPlugin(PluginOrgDTO plugin);
|
||||
|
||||
Flux<Organization> installDefaultPlugins(List<Plugin> plugins);
|
||||
|
||||
Mono<Organization> uninstallPlugin(PluginOrgDTO plugin);
|
||||
|
||||
Mono<Plugin> findByName(String name);
|
||||
|
|
@ -30,9 +33,13 @@ public interface PluginService extends CrudService<Plugin, String> {
|
|||
|
||||
Mono<Map> getFormConfig(String pluginId);
|
||||
|
||||
Flux<Plugin> getAllRemotePlugins();
|
||||
|
||||
Mono<Map> loadPluginResource(String pluginId, String resourcePath);
|
||||
|
||||
Mono<Map> getEditorConfigLabelMap(String pluginId);
|
||||
|
||||
Map loadEditorPluginResourceUqi(Plugin plugin);
|
||||
|
||||
Flux<Plugin> saveAll(Iterable<Plugin> plugins);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<PluginRepository, Plugin, Str
|
|||
.switchIfEmpty(Mono.empty());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<Organization> installDefaultPlugins(List<Plugin> plugins) {
|
||||
final List<OrganizationPlugin> 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<Organization> uninstallPlugin(PluginOrgDTO pluginDTO) {
|
||||
if (pluginDTO.getPluginId() == null) {
|
||||
|
|
@ -626,6 +642,16 @@ public class PluginServiceImpl extends BaseService<PluginRepository, Plugin, Str
|
|||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<Plugin> saveAll(Iterable<Plugin> plugins) {
|
||||
return repository.saveAll(plugins);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<Plugin> 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<PluginRepository, Plugin, Str
|
|||
public Mono<Map> 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);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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<Map<PluginIdentifier, Plugin>> availablePluginsMono =
|
||||
pluginService
|
||||
.getAllRemotePlugins()
|
||||
.collect(Collectors.toMap(
|
||||
plugin -> new PluginIdentifier(plugin.getPluginName(), plugin.getVersion()),
|
||||
plugin -> plugin
|
||||
));
|
||||
|
||||
final Mono<Map<PluginIdentifier, Plugin>> newPluginsMono = getRemotePlugins();
|
||||
|
||||
Mono.zip(availablePluginsMono, newPluginsMono)
|
||||
.flatMapMany(tuple -> {
|
||||
final Map<PluginIdentifier, Plugin> availablePlugins = tuple.getT1();
|
||||
final Map<PluginIdentifier, Plugin> newPlugins = tuple.getT2();
|
||||
final List<Plugin> updatablePlugins = new ArrayList<>();
|
||||
final List<Plugin> 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<Plugin> updatedPluginsFlux = pluginService.saveAll(updatablePlugins);
|
||||
final Flux<Organization> organizationFlux = pluginService.saveAll(insertablePlugins)
|
||||
.filter(Plugin::getDefaultInstall)
|
||||
.collectList()
|
||||
.flatMapMany(pluginService::installDefaultPlugins);
|
||||
|
||||
return updatedPluginsFlux.zipWith(organizationFlux);
|
||||
})
|
||||
.subscribeOn(Schedulers.single())
|
||||
.subscribe();
|
||||
}
|
||||
|
||||
private Mono<Map<PluginIdentifier, Plugin>> 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<ResponseDTO<List<Plugin>>>() {
|
||||
}))
|
||||
.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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ mvn clean package "$@"
|
|||
|
||||
if [ $? -eq 0 ]
|
||||
then
|
||||
echo "mvn Successfull"
|
||||
echo "mvn Successful"
|
||||
else
|
||||
echo "mvn Failed"
|
||||
exit 1
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user