Mongo Plugin works here. Barring the scenarios where the query json contains special characters in keys ($, .) it works properly.
This commit is contained in:
parent
0473e3d48e
commit
84837fe57f
|
|
@ -35,7 +35,16 @@ public class ActionConfiguration {
|
|||
HttpMethod httpMethod;
|
||||
|
||||
// DB action fields
|
||||
String query;
|
||||
|
||||
/*
|
||||
* For SQL plugins, the query field would be of the following format :
|
||||
* {
|
||||
* "cmd" : "select * from users;"
|
||||
* }
|
||||
* For noSQL plugins, the query json would be constructed according to
|
||||
* the requirements of the plugin.
|
||||
*/
|
||||
Map<String, Object> query;
|
||||
|
||||
/*
|
||||
* Future plugins could require more fields that are not covered above.
|
||||
|
|
|
|||
|
|
@ -23,4 +23,9 @@ public class ResourceConfiguration {
|
|||
|
||||
//For REST API
|
||||
List<Property> headers;
|
||||
|
||||
//This field is for plugins which allow the database name to be specified outside of the connection URL. The
|
||||
//expectation from the plugins is that if the database name has been provided via this field, the database name
|
||||
//should be according to this, else if database name is null, pick the database name from the URL.
|
||||
String databaseName;
|
||||
}
|
||||
|
|
|
|||
84
app/server/appsmith-plugins/mongoPlugin/pom.xml
Normal file
84
app/server/appsmith-plugins/mongoPlugin/pom.xml
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
<?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>mongoPlugin</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
|
||||
<name>mongoPlugin</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>mongo-plugin</plugin.id>
|
||||
<plugin.class>com.external.plugins.MongoPlugin</plugin.class>
|
||||
<plugin.version>1.0-SNAPSHOT</plugin.version>
|
||||
<plugin.provider>tech@appsmith.com</plugin.provider>
|
||||
<plugin.dependencies/>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.11</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.pf4j</groupId>
|
||||
<artifactId>pf4j-spring</artifactId>
|
||||
<version>0.5.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.appsmith</groupId>
|
||||
<artifactId>interfaces</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.8</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mongodb</groupId>
|
||||
<artifactId>mongo-java-driver</artifactId>
|
||||
<version>3.11.1</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.8.1</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>3.1.2</version>
|
||||
<configuration>
|
||||
<archive>
|
||||
<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>
|
||||
<Plugin-Dependencies>${plugin.dependencies}</Plugin-Dependencies>
|
||||
</manifestEntries>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
130
app/server/appsmith-plugins/mongoPlugin/src/main/java/com/external/plugins/MongoPlugin.java
vendored
Normal file
130
app/server/appsmith-plugins/mongoPlugin/src/main/java/com/external/plugins/MongoPlugin.java
vendored
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
package com.external.plugins;
|
||||
|
||||
import com.appsmith.external.models.ActionConfiguration;
|
||||
import com.appsmith.external.models.ActionExecutionResult;
|
||||
import com.appsmith.external.models.ResourceConfiguration;
|
||||
import com.appsmith.external.plugins.BasePlugin;
|
||||
import com.appsmith.external.plugins.PluginExecutor;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.mongodb.MongoClient;
|
||||
import com.mongodb.MongoClientURI;
|
||||
import com.mongodb.client.MongoDatabase;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.bson.Document;
|
||||
import org.bson.conversions.Bson;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
import org.pf4j.Extension;
|
||||
import org.pf4j.PluginWrapper;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
@Slf4j
|
||||
public class MongoPlugin extends BasePlugin {
|
||||
|
||||
private static ObjectMapper objectMapper;
|
||||
|
||||
public MongoPlugin(PluginWrapper wrapper) {
|
||||
super(wrapper);
|
||||
this.objectMapper = new ObjectMapper();
|
||||
}
|
||||
|
||||
@Slf4j
|
||||
@Extension
|
||||
public static class MongoPluginExecutor implements PluginExecutor {
|
||||
|
||||
/**
|
||||
* For reference on creating the json queries for Mongo please head to
|
||||
* https://docs.huihoo.com/mongodb/3.4/reference/command/index.html
|
||||
*
|
||||
* @param connection : This is the connection that is established to the data source. This connection is according
|
||||
* to the parameters in Resource Configuration
|
||||
* @param resourceConfiguration : These are the configurations which have been used to create a Resource from a Plugin
|
||||
* @param actionConfiguration : These are the configurations which have been used to create an Action from a Resource.
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Mono<ActionExecutionResult> execute(Object connection,
|
||||
ResourceConfiguration resourceConfiguration,
|
||||
ActionConfiguration actionConfiguration) {
|
||||
|
||||
ActionExecutionResult result = new ActionExecutionResult();
|
||||
MongoClient mongoClient = (MongoClient) connection;
|
||||
if (mongoClient == null) {
|
||||
return Mono.error(new Exception("Mongo Client is null."));
|
||||
}
|
||||
|
||||
MongoClientURI mongoClientURI= new MongoClientURI(resourceConfiguration.getUrl());
|
||||
|
||||
String databaseName = resourceConfiguration.getDatabaseName();
|
||||
if (databaseName == null) {
|
||||
databaseName = mongoClientURI.getDatabase();
|
||||
}
|
||||
|
||||
MongoDatabase database = mongoClient.getDatabase(databaseName);
|
||||
|
||||
Bson command = new Document(actionConfiguration.getQuery());
|
||||
|
||||
try {
|
||||
|
||||
Document mongoOutput = database.runCommand(command);
|
||||
|
||||
JSONObject outputJson = new JSONObject(mongoOutput.toJson());
|
||||
//The output json contains the key "ok". This is the status of the command
|
||||
BigInteger status = outputJson.getBigInteger("ok");
|
||||
JSONArray headerArray = new JSONArray();
|
||||
if (BigInteger.ONE == status) {
|
||||
//The json contains key "cursor" when find command was issued and there are 1 or more results. In case
|
||||
//there are no results for find, this key is not present in the result json.
|
||||
if (outputJson.has("cursor")) {
|
||||
JSONArray outputResult = outputJson.getJSONObject("cursor").getJSONArray("firstBatch");
|
||||
result.setBody(objectMapper.readTree(outputResult.toString()));
|
||||
}
|
||||
//The json contains key "n" when insert/update command is issued. "n" for update signifies the no of
|
||||
//documents selected for update. "n" in case of insert signifies the number of documents inserted.
|
||||
if (outputJson.has("n")) {
|
||||
JSONObject body = new JSONObject().put("n", outputJson.getBigInteger("n"));
|
||||
headerArray.put(body);
|
||||
}
|
||||
//The json key constains key "nModified" in case of update command. This signifies the no of
|
||||
//documents updated.
|
||||
if (outputJson.has("nModified")) {
|
||||
JSONObject body = new JSONObject().put("nModified", outputJson.getBigInteger("nModified"));
|
||||
headerArray.put(body);
|
||||
}
|
||||
|
||||
/** TODO
|
||||
* Go through all the possible fields that are returned in the output JSON and add all the fields
|
||||
* that are important to the headerArray.
|
||||
*/
|
||||
}
|
||||
|
||||
JSONObject statusJson = new JSONObject().put("ok", status);
|
||||
headerArray.put(statusJson);
|
||||
result.setHeaders(objectMapper.readTree(headerArray.toString()));
|
||||
} catch (Exception e) {
|
||||
return Mono.error(e);
|
||||
}
|
||||
|
||||
return Mono.just(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object resourceCreate(ResourceConfiguration resourceConfiguration) {
|
||||
|
||||
MongoClientURI mongoClientURI= new MongoClientURI(resourceConfiguration.getUrl());
|
||||
return new MongoClient(mongoClientURI);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resourceDestroy(Object connection) {
|
||||
MongoClient mongoClient = (MongoClient) connection;
|
||||
if (mongoClient != null) {
|
||||
mongoClient.close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
18
app/server/appsmith-plugins/mongoPlugin/src/test/java/com/external/plugins/MongoPluginTest.java
vendored
Normal file
18
app/server/appsmith-plugins/mongoPlugin/src/test/java/com/external/plugins/MongoPluginTest.java
vendored
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
package com.external.plugins;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* Unit test for simple App.
|
||||
*/
|
||||
public class MongoPluginTest {
|
||||
/**
|
||||
* Rigorous Test :-)
|
||||
*/
|
||||
@Test
|
||||
public void shouldAnswerWithTrue() {
|
||||
assertTrue(true);
|
||||
}
|
||||
}
|
||||
|
|
@ -17,6 +17,7 @@
|
|||
<modules>
|
||||
<module>postgresPlugin</module>
|
||||
<module>restApiPlugin</module>
|
||||
<module>mongoPlugin</module>
|
||||
</modules>
|
||||
|
||||
</project>
|
||||
|
|
@ -2,14 +2,11 @@ package com.external.plugins;
|
|||
|
||||
import com.appsmith.external.models.ActionConfiguration;
|
||||
import com.appsmith.external.models.ActionExecutionResult;
|
||||
import com.appsmith.external.models.Param;
|
||||
import com.appsmith.external.models.ResourceConfiguration;
|
||||
import com.appsmith.external.plugins.BasePlugin;
|
||||
import com.appsmith.external.plugins.PluginExecutor;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.json.JSONObject;
|
||||
import org.pf4j.Extension;
|
||||
import org.pf4j.PluginException;
|
||||
import org.pf4j.PluginWrapper;
|
||||
|
|
@ -24,7 +21,7 @@ import java.sql.SQLException;
|
|||
import java.sql.Statement;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Slf4j
|
||||
public class PostgresPlugin extends BasePlugin {
|
||||
|
|
@ -38,6 +35,13 @@ public class PostgresPlugin extends BasePlugin {
|
|||
this.objectMapper = new ObjectMapper();
|
||||
}
|
||||
|
||||
/**
|
||||
* Postgres plugin receives the query as json of the following format :
|
||||
* {
|
||||
* "cmd" : "select * from users;"
|
||||
* }
|
||||
*/
|
||||
|
||||
@Slf4j
|
||||
@Extension
|
||||
public static class PostgresPluginExecutor implements PluginExecutor {
|
||||
|
|
@ -53,8 +57,9 @@ public class PostgresPlugin extends BasePlugin {
|
|||
ArrayList list = new ArrayList(50);
|
||||
try {
|
||||
Statement statement = conn.createStatement();
|
||||
|
||||
ResultSet resultSet = statement.executeQuery(actionConfiguration.getQuery());
|
||||
Map<String, Object> queryJson = actionConfiguration.getQuery();
|
||||
String query = (String) queryJson.get("cmd");
|
||||
ResultSet resultSet = statement.executeQuery(query);
|
||||
ResultSetMetaData metaData = resultSet.getMetaData();
|
||||
Integer colCount = metaData.getColumnCount();
|
||||
while (resultSet.next()) {
|
||||
|
|
@ -90,7 +95,8 @@ public class PostgresPlugin extends BasePlugin {
|
|||
} catch (SQLException e) {
|
||||
log.error("", e);
|
||||
}
|
||||
return conn;
|
||||
// Connection wasn't created. Return null
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -18,7 +18,8 @@ public enum AppsmithError {
|
|||
UNAUTHORIZED_ACCESS(401, 4002, "Unauthorized access"),
|
||||
INTERNAL_SERVER_ERROR(500, 5000, "Internal server error while processing request"),
|
||||
REPOSITORY_SAVE_FAILED(500, 5001, "Repository save failed."),
|
||||
PLUGIN_INSTALLATION_FAILED_DOWNLOAD_ERROR(500, 5002, "Due to error in downloading the plugin from remote repository, plugin installation has failed. Check the jar location and try again.");
|
||||
PLUGIN_INSTALLATION_FAILED_DOWNLOAD_ERROR(500, 5002, "Due to error in downloading the plugin from remote repository, plugin installation has failed. Check the jar location and try again."),
|
||||
PLUGIN_RUN_FAILED(500, 5003, "Plugin execution failed with error {0}");
|
||||
|
||||
|
||||
private Integer httpErrorCode;
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import com.appsmith.server.domains.Page;
|
|||
import com.appsmith.server.domains.PageAction;
|
||||
import com.appsmith.server.domains.Plugin;
|
||||
import com.appsmith.server.domains.Resource;
|
||||
import com.appsmith.server.domains.ResourceContext;
|
||||
import com.appsmith.server.domains.User;
|
||||
import com.appsmith.server.dtos.ExecuteActionDTO;
|
||||
import com.appsmith.server.exceptions.AppsmithError;
|
||||
|
|
@ -171,15 +170,15 @@ public class ActionServiceImpl extends BaseService<ActionRepository, Action, Str
|
|||
resourceConfiguration = resource.getResourceConfiguration();
|
||||
actionConfiguration = action.getActionConfiguration();
|
||||
}
|
||||
|
||||
return resourceContextService
|
||||
.getResourceContext(resource.getId())
|
||||
//Now that we have the context (connection details, execute the action
|
||||
//Now that we have the context (connection details, execute the action
|
||||
.flatMap(resourceContext -> pluginExecutor.execute(
|
||||
resourceContext.getConnection(),
|
||||
resourceConfiguration,
|
||||
actionConfiguration));
|
||||
}))
|
||||
.onErrorResume(e -> Mono.error(new AppsmithException(AppsmithError.PLUGIN_RUN_FAILED, e.getMessage())))
|
||||
.flatMap(obj -> obj);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,9 @@ url_allow = true {
|
|||
p = op.permission
|
||||
}
|
||||
|
||||
# This is a global list of all the routes for all controllers. Any new controller that is written must
|
||||
# carry an entry in this array. OPA performs ACL based on an intersection of these entries and permissions
|
||||
# for a user + permissions inherited via the groups that the user is a part of.
|
||||
allowed_operations = [
|
||||
{"method": "POST", "resource": "users", "permission": "create:users"},
|
||||
{"method": "GET", "resource": "users", "permission": "read:users"},
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user