Merge branch 'mongo-changes' into 'master'

#42

See merge request theappsmith/internal-tools-server!9
This commit is contained in:
Trisha Anand 2019-09-03 11:36:49 +00:00
commit 6c90ce2561
37 changed files with 173 additions and 137 deletions

View File

@ -3,8 +3,8 @@ package com.appsmith.server.configurations;
import com.appsmith.server.domains.LoginSource; import com.appsmith.server.domains.LoginSource;
import com.appsmith.server.domains.User; import com.appsmith.server.domains.User;
import com.appsmith.server.domains.UserState; import com.appsmith.server.domains.UserState;
import com.appsmith.server.services.UserService;
import com.appsmith.server.services.TenantService; import com.appsmith.server.services.TenantService;
import com.appsmith.server.services.UserService;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClient; import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;

View File

@ -1,9 +1,9 @@
package com.appsmith.server.configurations; package com.appsmith.server.configurations;
import com.appsmith.server.services.UserService;
import com.appsmith.server.constants.Security; import com.appsmith.server.constants.Security;
import com.appsmith.server.services.TenantService; import com.appsmith.server.services.TenantService;
import com.appsmith.server.services.UserService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;

View File

@ -2,12 +2,17 @@ package com.appsmith.server.controllers;
import com.appsmith.server.domains.BaseDomain; import com.appsmith.server.domains.BaseDomain;
import com.appsmith.server.dtos.ResponseDto; import com.appsmith.server.dtos.ResponseDto;
import com.appsmith.server.services.CrudService;
import com.appsmith.server.exceptions.AppsmithException; import com.appsmith.server.exceptions.AppsmithException;
import com.appsmith.server.services.CrudService;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import reactor.core.publisher.Flux; import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;

View File

@ -1,8 +1,8 @@
package com.appsmith.server.controllers; package com.appsmith.server.controllers;
import com.appsmith.server.constants.Url;
import com.appsmith.server.domains.Layout; import com.appsmith.server.domains.Layout;
import com.appsmith.server.services.LayoutService; import com.appsmith.server.services.LayoutService;
import com.appsmith.server.constants.Url;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;

View File

@ -1,14 +1,18 @@
package com.appsmith.server.controllers; package com.appsmith.server.controllers;
import com.appsmith.server.constants.Url;
import com.appsmith.server.domains.Plugin; import com.appsmith.server.domains.Plugin;
import com.appsmith.server.domains.Tenant; import com.appsmith.server.domains.Tenant;
import com.appsmith.server.dtos.PluginTenantDTO; import com.appsmith.server.dtos.PluginTenantDTO;
import com.appsmith.server.dtos.ResponseDto; import com.appsmith.server.dtos.ResponseDto;
import com.appsmith.server.services.PluginService; import com.appsmith.server.services.PluginService;
import com.appsmith.server.constants.Url;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import javax.validation.Valid; import javax.validation.Valid;

View File

@ -1,11 +1,15 @@
package com.appsmith.server.controllers; package com.appsmith.server.controllers;
import com.appsmith.server.constants.Url;
import com.appsmith.server.domains.Query; import com.appsmith.server.domains.Query;
import com.appsmith.server.dtos.CommandQueryParams; import com.appsmith.server.dtos.CommandQueryParams;
import com.appsmith.server.services.QueryService; import com.appsmith.server.services.QueryService;
import com.appsmith.server.constants.Url;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux; import reactor.core.publisher.Flux;
@RestController @RestController

View File

@ -1,8 +1,8 @@
package com.appsmith.server.controllers; package com.appsmith.server.controllers;
import com.appsmith.server.services.ResourceService;
import com.appsmith.server.constants.Url; import com.appsmith.server.constants.Url;
import com.appsmith.server.domains.Resource; import com.appsmith.server.domains.Resource;
import com.appsmith.server.services.ResourceService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;

View File

@ -1,8 +1,8 @@
package com.appsmith.server.controllers; package com.appsmith.server.controllers;
import com.appsmith.server.constants.Url;
import com.appsmith.server.domains.Setting; import com.appsmith.server.domains.Setting;
import com.appsmith.server.services.SettingService; import com.appsmith.server.services.SettingService;
import com.appsmith.server.constants.Url;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;

View File

@ -1,7 +1,7 @@
package com.appsmith.server.controllers; package com.appsmith.server.controllers;
import com.appsmith.server.domains.Tenant;
import com.appsmith.server.constants.Url; import com.appsmith.server.constants.Url;
import com.appsmith.server.domains.Tenant;
import com.appsmith.server.services.TenantService; import com.appsmith.server.services.TenantService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;

View File

@ -1,9 +1,9 @@
package com.appsmith.server.controllers; package com.appsmith.server.controllers;
import com.appsmith.server.constants.Url;
import com.appsmith.server.domains.Widget; import com.appsmith.server.domains.Widget;
import com.appsmith.server.dtos.ResponseDto; import com.appsmith.server.dtos.ResponseDto;
import com.appsmith.server.services.WidgetService; import com.appsmith.server.services.WidgetService;
import com.appsmith.server.constants.Url;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;

View File

@ -5,7 +5,6 @@ import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
import lombok.ToString; import lombok.ToString;
import org.springframework.data.mongodb.core.index.Indexed; import org.springframework.data.mongodb.core.index.Indexed;
import org.springframework.data.mongodb.core.mapping.DBRef;
import org.springframework.data.mongodb.core.mapping.Document; import org.springframework.data.mongodb.core.mapping.Document;
@Getter @Getter
@ -17,8 +16,9 @@ public class Action extends BaseDomain {
@Indexed(unique = true) @Indexed(unique = true)
String name; String name;
@DBRef String resourceId;
Resource resource;
String pluginId;
ActionConfiguration actionConfiguration; ActionConfiguration actionConfiguration;
} }

View File

@ -3,7 +3,11 @@ package com.appsmith.server.domains;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.ToString; import lombok.ToString;
import org.springframework.data.annotation.*; import org.springframework.data.annotation.CreatedBy;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.LastModifiedBy;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.domain.Persistable; import org.springframework.data.domain.Persistable;
import java.util.Date; import java.util.Date;

View File

@ -5,7 +5,6 @@ import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
import lombok.ToString; import lombok.ToString;
import org.springframework.data.mongodb.core.index.Indexed; import org.springframework.data.mongodb.core.index.Indexed;
import org.springframework.data.mongodb.core.mapping.DBRef;
import org.springframework.data.mongodb.core.mapping.Document; import org.springframework.data.mongodb.core.mapping.Document;
@Getter @Getter
@ -17,11 +16,9 @@ public class Resource extends BaseDomain {
@Indexed(unique = true) @Indexed(unique = true)
String name; String name;
@DBRef String pluginId;
Plugin plugin;
@DBRef String tenantId;
Tenant tenant;
ResourceConfiguration resourceConfiguration; ResourceConfiguration resourceConfiguration;

View File

@ -5,7 +5,6 @@ import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
import lombok.ToString; import lombok.ToString;
import org.springframework.data.mongodb.core.mapping.DBRef;
@Getter @Getter
@Setter @Setter
@ -13,8 +12,7 @@ import org.springframework.data.mongodb.core.mapping.DBRef;
@NoArgsConstructor @NoArgsConstructor
public class TenantPlugin extends BaseDomain { public class TenantPlugin extends BaseDomain {
@DBRef private String pluginId;
private Plugin plugin;
TenantPluginStatus status; TenantPluginStatus status;

View File

@ -19,7 +19,7 @@ import java.util.stream.Collectors;
@ToString @ToString
@NoArgsConstructor @NoArgsConstructor
@Document @Document
public class User extends BaseDomain implements UserDetails { public class User extends BaseDomain implements UserDetails {
private String name; private String name;

View File

@ -1,6 +1,10 @@
package com.appsmith.server.dtos; package com.appsmith.server.dtos;
import lombok.*; import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
@Getter @Getter
@Setter @Setter

View File

@ -6,6 +6,6 @@ import lombok.Setter;
@Getter @Getter
@Setter @Setter
public class PluginTenantDTO { public class PluginTenantDTO {
String name; String pluginId;
TenantPluginStatus status; TenantPluginStatus status;
} }

View File

@ -1,6 +1,10 @@
package com.appsmith.server.dtos; package com.appsmith.server.dtos;
import lombok.*; import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import java.io.Serializable; import java.io.Serializable;

View File

@ -9,6 +9,9 @@ public enum AppsmithError {
NO_RESOURCE_FOUND(404, 1000, "Unable to find {0} with id {1}"), NO_RESOURCE_FOUND(404, 1000, "Unable to find {0} with id {1}"),
INVALID_PARAMETER(400, 4000, "Invalid parameter {0} provided in the input"), INVALID_PARAMETER(400, 4000, "Invalid parameter {0} provided in the input"),
PLUGIN_NOT_INSTALLED(400, 4001, "Plugin not installed for tenant {0}"),
PLUGIN_ID_NOT_GIVEN(400, 4002, "Missing plugin id. Please input correct plugin id"),
RESOURCE_ID_NOT_GIVEN(400, 4003, "Missing resource id. Please input correct resource id"),
INTERNAL_SERVER_ERROR(500, 5000, "Internal server error while processing request"); INTERNAL_SERVER_ERROR(500, 5000, "Internal server error while processing request");
private Integer httpErrorCode; private Integer httpErrorCode;

View File

@ -1,6 +1,7 @@
package com.appsmith.server.exceptions; package com.appsmith.server.exceptions;
import com.appsmith.server.dtos.ResponseDto; import com.appsmith.server.dtos.ResponseDto;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ExceptionHandler;
@ -13,20 +14,23 @@ import reactor.core.publisher.Mono;
* sending it to the client. * sending it to the client.
*/ */
@ControllerAdvice @ControllerAdvice
@Slf4j
public class GlobalExceptionHandler { public class GlobalExceptionHandler {
/** /**
* This function only catches the AppsmithException type and formats it into ResponseEntity<ErrorDTO> object * This function only catches the AppsmithException type and formats it into ResponseEntity<ErrorDTO> object
* Ideally, we should only be throwing AppsmithException from our code. This ensures that we can standardize * Ideally, we should only be throwing AppsmithException from our code. This ensures that we can standardize
* and set proper error messages and codes. * and set proper error messages and codes.
* @param e AppsmithException that will be caught by the function *
* @param e AppsmithException that will be caught by the function
* @param exchange ServerWebExchange contract in order to extract the response and set the http status code * @param exchange ServerWebExchange contract in order to extract the response and set the http status code
* @return Mono<ResponseDto<ErrorDTO>> * @return Mono<ResponseDto < ErrorDTO>>
*/ */
@ExceptionHandler @ExceptionHandler
@ResponseBody @ResponseBody
public Mono<ResponseDto<ErrorDTO>> catchAppsmithException(AppsmithException e, ServerWebExchange exchange) { public Mono<ResponseDto<ErrorDTO>> catchAppsmithException(AppsmithException e, ServerWebExchange exchange) {
exchange.getResponse().setStatusCode(HttpStatus.resolve(e.getHttpStatus())); exchange.getResponse().setStatusCode(HttpStatus.resolve(e.getHttpStatus()));
log.error("", e);
return Mono.just(new ResponseDto<>(e.getHttpStatus(), new ErrorDTO(e.getAppErrorCode(), e.getMessage()), null, false)); return Mono.just(new ResponseDto<>(e.getHttpStatus(), new ErrorDTO(e.getAppErrorCode(), e.getMessage()), null, false));
} }
@ -34,14 +38,15 @@ public class GlobalExceptionHandler {
* This function catches the generic Exception class and is meant to be a catch all to ensure that we don't leak * This function catches the generic Exception class and is meant to be a catch all to ensure that we don't leak
* any information to the client. Ideally, the function #catchAppsmithException should be used * any information to the client. Ideally, the function #catchAppsmithException should be used
* *
* @param e Exception that will be caught by the function * @param e Exception that will be caught by the function
* @param exchange ServerWebExchange contract in order to extract the response and set the http status code * @param exchange ServerWebExchange contract in order to extract the response and set the http status code
* @return Mono<ResponseDto<ErrorDTO>> * @return Mono<ResponseDto < ErrorDTO>>
*/ */
@ExceptionHandler @ExceptionHandler
@ResponseBody @ResponseBody
public Mono<ResponseDto<ErrorDTO>> catchException(Exception e, ServerWebExchange exchange) { public Mono<ResponseDto<ErrorDTO>> catchException(Exception e, ServerWebExchange exchange) {
exchange.getResponse().setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR); exchange.getResponse().setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
log.error("", e);
return Mono.just(new ResponseDto<>(HttpStatus.INTERNAL_SERVER_ERROR.value(), new ErrorDTO(AppsmithError.INTERNAL_SERVER_ERROR.getHttpErrorCode(), return Mono.just(new ResponseDto<>(HttpStatus.INTERNAL_SERVER_ERROR.value(), new ErrorDTO(AppsmithError.INTERNAL_SERVER_ERROR.getHttpErrorCode(),
AppsmithError.INTERNAL_SERVER_ERROR.getMessage()), null, false)); AppsmithError.INTERNAL_SERVER_ERROR.getMessage()), null, false));
} }

View File

@ -59,7 +59,7 @@ public class MDCFilter implements WebFilter {
private Mono<Void> addContextToHttpResponse(final ServerHttpResponse response) { private Mono<Void> addContextToHttpResponse(final ServerHttpResponse response) {
return Mono.subscriberContext().doOnNext(ctx -> { return Mono.subscriberContext().doOnNext(ctx -> {
if(!ctx.hasKey(LogHelper.CONTEXT_MAP)) { if (!ctx.hasKey(LogHelper.CONTEXT_MAP)) {
return; return;
} }
@ -67,12 +67,12 @@ public class MDCFilter implements WebFilter {
// Add all the request MDC keys to the response object // Add all the request MDC keys to the response object
ctx.<Map<String, String>>get(LogHelper.CONTEXT_MAP) ctx.<Map<String, String>>get(LogHelper.CONTEXT_MAP)
.forEach((key, value) -> { .forEach((key, value) -> {
if(!key.contains(REQUEST_ID_LOG)) { if (!key.contains(REQUEST_ID_LOG)) {
httpHeaders.add(MDC_HEADER_PREFIX + key, value); httpHeaders.add(MDC_HEADER_PREFIX + key, value);
} else { } else {
httpHeaders.add(REQUEST_ID_HEADER, value); httpHeaders.add(REQUEST_ID_HEADER, value);
} }
}); });
}).then(); }).then();
} }

View File

@ -1,14 +1,19 @@
package com.appsmith.server.plugins; package com.appsmith.server.plugins;
import com.appsmith.server.services.PluginExecutor;
import com.appsmith.server.domains.Query; import com.appsmith.server.domains.Query;
import com.appsmith.server.dtos.CommandQueryParams; import com.appsmith.server.dtos.CommandQueryParams;
import com.appsmith.server.services.PluginExecutor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import reactor.core.publisher.Flux; import reactor.core.publisher.Flux;
import java.sql.*; import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;

View File

@ -1,9 +1,9 @@
package com.appsmith.server.plugins; package com.appsmith.server.plugins;
import com.appsmith.server.services.PluginExecutor;
import com.appsmith.server.domains.Property; import com.appsmith.server.domains.Property;
import com.appsmith.server.domains.Query; import com.appsmith.server.domains.Query;
import com.appsmith.server.dtos.CommandQueryParams; import com.appsmith.server.dtos.CommandQueryParams;
import com.appsmith.server.services.PluginExecutor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.minidev.json.JSONObject; import net.minidev.json.JSONObject;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;

View File

@ -7,4 +7,6 @@ import reactor.core.publisher.Mono;
@Repository @Repository
public interface PluginRepository extends BaseRepository<Plugin, String> { public interface PluginRepository extends BaseRepository<Plugin, String> {
Mono<Plugin> findByName(String name); Mono<Plugin> findByName(String name);
Mono<Plugin> findById(String id);
} }

View File

@ -7,4 +7,6 @@ import reactor.core.publisher.Mono;
@Repository @Repository
public interface ResourceRepository extends BaseRepository<Resource, String> { public interface ResourceRepository extends BaseRepository<Resource, String> {
Mono<Resource> findByName(String name); Mono<Resource> findByName(String name);
Mono<Resource> findById(String id);
} }

View File

@ -7,4 +7,6 @@ import reactor.core.publisher.Mono;
@Repository @Repository
public interface TenantRepository extends BaseRepository<Tenant, String> { public interface TenantRepository extends BaseRepository<Tenant, String> {
Mono<Tenant> findByName(String name); Mono<Tenant> findByName(String name);
Mono<Tenant> findByIdAndPluginsPluginId(String tenantId, String pluginId);
} }

View File

@ -8,5 +8,6 @@ import reactor.core.publisher.Mono;
public interface UserRepository extends BaseRepository<User, String> { public interface UserRepository extends BaseRepository<User, String> {
Mono<User> findByName(String name); Mono<User> findByName(String name);
Mono<User> findByEmail(String email); Mono<User> findByEmail(String email);
} }

View File

@ -1,7 +1,9 @@
package com.appsmith.server.services; package com.appsmith.server.services;
import com.appsmith.server.domains.Action; import com.appsmith.server.domains.Action;
import com.appsmith.server.domains.Plugin;
import com.appsmith.server.domains.Resource; import com.appsmith.server.domains.Resource;
import com.appsmith.server.exceptions.AppsmithError;
import com.appsmith.server.exceptions.AppsmithException; import com.appsmith.server.exceptions.AppsmithException;
import com.appsmith.server.repositories.ActionRepository; import com.appsmith.server.repositories.ActionRepository;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -20,25 +22,32 @@ public class ActionServiceImpl extends BaseService<ActionRepository, Action, Str
private final ActionRepository repository; private final ActionRepository repository;
private final ResourceService resourceService; private final ResourceService resourceService;
private final PluginService pluginService;
@Autowired @Autowired
public ActionServiceImpl(Scheduler scheduler, MongoConverter mongoConverter, ReactiveMongoTemplate reactiveMongoTemplate, ActionRepository repository, ResourceService resourceService) { public ActionServiceImpl(Scheduler scheduler, MongoConverter mongoConverter, ReactiveMongoTemplate reactiveMongoTemplate, ActionRepository repository, ResourceService resourceService, PluginService pluginService) {
super(scheduler, mongoConverter, reactiveMongoTemplate, repository); super(scheduler, mongoConverter, reactiveMongoTemplate, repository);
this.repository = repository; this.repository = repository;
this.resourceService = resourceService; this.resourceService = resourceService;
this.pluginService = pluginService;
} }
@Override @Override
public Mono<Action> create(@NotNull Action action) throws AppsmithException { public Mono<Action> create(@NotNull Action action) throws AppsmithException {
if (action.getId() != null) { if (action.getId() != null) {
throw new AppsmithException("During create action, Id is not null. Can't create new action."); throw new AppsmithException("During create action, Id is not null. Can't create new action.");
} else if (action.getResourceId() == null) {
throw new AppsmithException(AppsmithError.RESOURCE_ID_NOT_GIVEN);
} }
Mono<Resource> resourceMono = resourceService.findByName(action.getResource().getName()); Mono<Resource> resourceMono = resourceService.findById(action.getResourceId());
Mono<Plugin> pluginMono = resourceMono.flatMap(resource -> pluginService.findById(resource.getPluginId()));
return resourceMono
.map(resource -> { return pluginMono
action.setResource(resource); //Set plugin in the action before saving.
.map(plugin -> {
action.setPluginId(plugin.getId());
return action; return action;
}) })
.flatMap(repository::save); .flatMap(repository::save);

View File

@ -4,7 +4,6 @@ import com.appsmith.server.domains.BaseDomain;
import com.appsmith.server.exceptions.AppsmithError; import com.appsmith.server.exceptions.AppsmithError;
import com.appsmith.server.exceptions.AppsmithException; import com.appsmith.server.exceptions.AppsmithException;
import com.appsmith.server.repositories.BaseRepository; import com.appsmith.server.repositories.BaseRepository;
import com.mongodb.BasicDBObject; import com.mongodb.BasicDBObject;
import com.mongodb.DBObject; import com.mongodb.DBObject;
import org.springframework.data.mongodb.core.ReactiveMongoTemplate; import org.springframework.data.mongodb.core.ReactiveMongoTemplate;

View File

@ -1,11 +1,11 @@
package com.appsmith.server.services; package com.appsmith.server.services;
import com.github.mustachejava.DefaultMustacheFactory;
import com.github.mustachejava.Mustache;
import com.github.mustachejava.MustacheFactory;
import com.appsmith.server.domains.Query; import com.appsmith.server.domains.Query;
import com.appsmith.server.dtos.CommandQueryParams; import com.appsmith.server.dtos.CommandQueryParams;
import com.appsmith.server.dtos.Param; import com.appsmith.server.dtos.Param;
import com.github.mustachejava.DefaultMustacheFactory;
import com.github.mustachejava.Mustache;
import com.github.mustachejava.MustacheFactory;
import reactor.core.publisher.Flux; import reactor.core.publisher.Flux;
import java.io.StringReader; import java.io.StringReader;

View File

@ -4,7 +4,6 @@ import com.appsmith.server.domains.Plugin;
import com.appsmith.server.domains.PluginType; import com.appsmith.server.domains.PluginType;
import com.appsmith.server.domains.Tenant; import com.appsmith.server.domains.Tenant;
import com.appsmith.server.dtos.PluginTenantDTO; import com.appsmith.server.dtos.PluginTenantDTO;
import com.appsmith.server.exceptions.AppsmithException;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
public interface PluginService extends CrudService<Plugin, String> { public interface PluginService extends CrudService<Plugin, String> {
@ -25,4 +24,6 @@ public interface PluginService extends CrudService<Plugin, String> {
public Mono<Plugin> findByName(String name); public Mono<Plugin> findByName(String name);
public Mono<Plugin> findById(String id);
} }

View File

@ -12,15 +12,11 @@ import com.appsmith.server.exceptions.AppsmithException;
import com.appsmith.server.repositories.PluginRepository; import com.appsmith.server.repositories.PluginRepository;
import com.appsmith.server.repositories.UserRepository; import com.appsmith.server.repositories.UserRepository;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.data.mongodb.core.ReactiveMongoTemplate; import org.springframework.data.mongodb.core.ReactiveMongoTemplate;
import org.springframework.data.mongodb.core.convert.MongoConverter; import org.springframework.data.mongodb.core.convert.MongoConverter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import reactor.core.scheduler.Scheduler; import reactor.core.scheduler.Scheduler;
@ -80,14 +76,17 @@ public class PluginServiceImpl extends BaseService<PluginRepository, Plugin, Str
@Override @Override
public Mono<Tenant> installPlugin(PluginTenantDTO pluginTenantDTO) { public Mono<Tenant> installPlugin(PluginTenantDTO pluginTenantDTO) {
return pluginRepository if (pluginTenantDTO.getPluginId() == null) {
.findByName(pluginTenantDTO.getName()) return Mono.error(new AppsmithException(AppsmithError.PLUGIN_ID_NOT_GIVEN));
.flatMap(plugin1 -> storeTenantPlugin(plugin1, pluginTenantDTO.getStatus())) }
return Mono.just(pluginTenantDTO)
.flatMap(plugin -> storeTenantPlugin(plugin, pluginTenantDTO.getStatus()))
.switchIfEmpty(Mono.empty()); .switchIfEmpty(Mono.empty());
} }
@Override @Override
public Mono<Tenant> uninstallPlugin(PluginTenantDTO plugin) { public Mono<Tenant> uninstallPlugin(PluginTenantDTO pluginDTO) {
/*TODO /*TODO
* Tenant & user association is being mocked here by forcefully * Tenant & user association is being mocked here by forcefully
* only using a hardcoded tenant. This needs to be replaced by * only using a hardcoded tenant. This needs to be replaced by
@ -102,36 +101,28 @@ public class PluginServiceImpl extends BaseService<PluginRepository, Plugin, Str
* be stored as part of user and this tenant should be used to store * be stored as part of user and this tenant should be used to store
* the installed plugin or to delete plugin during uninstallation. * the installed plugin or to delete plugin during uninstallation.
*/ */
Mono<Tenant> tenantMono = tenantService.findById(tenantId); if (pluginDTO.getPluginId() == null) {
return Mono.error(new AppsmithException(AppsmithError.PLUGIN_ID_NOT_GIVEN));
}
//Find the tenant using id and plugin id -> This is to find if the tenant has the plugin installed
Mono<Tenant> tenantMono = tenantService.findByIdAndPluginsPluginId(tenantId, pluginDTO.getPluginId());
return tenantMono return tenantMono
.switchIfEmpty(Mono.error(new AppsmithException(AppsmithError.PLUGIN_NOT_INSTALLED, tenantId)))
//In case the plugin is not found for the tenant, the tenantMono would not emit and the rest of the flow would stop
//i.e. the rest of the code flow would only happen when there is a plugin found for the tenant that can
//be uninstalled.
.map(tenant -> { .map(tenant -> {
List<TenantPlugin> tenantPluginList = tenant.getPlugins(); List<TenantPlugin> tenantPluginList = tenant.getPlugins();
if (tenantPluginList == null || tenantPluginList.isEmpty()) { tenantPluginList.removeIf(listPlugin -> listPlugin.getPluginId().equals(pluginDTO.getPluginId()));
return tenant; tenant.setPlugins(tenantPluginList);
}
for (TenantPlugin listPlugin : tenantPluginList) {
if (listPlugin.getPlugin().getName().equals(plugin.getName())) {
log.debug("Plugin {} found. Uninstalling now from Tenant {}.",
plugin.getName(), tenant.getName());
tenantPluginList.remove(listPlugin);
tenant.setPlugins(tenantPluginList);
return tenant;
}
}
log.debug("Plugin {} not found. Can't uninstall a plugin which is not installed",
plugin.getName());
return tenant; return tenant;
}) })
/* TODO
* Extra save is happening below in the edge case scenario of a plugin
* which needs to be removed from the installed list, didnt exist in this list
* to be begin with. Small optimization opportunity.
*/
.flatMap(tenantService::save); .flatMap(tenantService::save);
} }
private Mono<Tenant> storeTenantPlugin(Plugin plugin, TenantPluginStatus status) { private Mono<Tenant> storeTenantPlugin(PluginTenantDTO pluginDTO, TenantPluginStatus status) {
/*TODO /*TODO
* Tenant & user association is being mocked here by forcefully * Tenant & user association is being mocked here by forcefully
* only using a hardcoded tenant. This needs to be replaced by * only using a hardcoded tenant. This needs to be replaced by
@ -144,40 +135,37 @@ public class PluginServiceImpl extends BaseService<PluginRepository, Plugin, Str
* .map(Authentication::getPrincipal); * .map(Authentication::getPrincipal);
* Once the user has been pulled using this, tenant should already * Once the user has been pulled using this, tenant should already
* be stored as part of user and this tenant should be used to store * be stored as part of user and this tenant should be used to store
* the installed plugin or to delete plugin during uninstallation. * the installed plugin or to delete plugin during uninstalling.
*/ */
Mono<Tenant> tenantMono = tenantService.findById(tenantId);
Mono<Object> userObjectMono = ReactiveSecurityContextHolder.getContext() //Find the tenant using id and plugin id -> This is to find if the tenant already has the plugin installed
.map(SecurityContext::getAuthentication) Mono<Tenant> tenantMono = tenantService.findByIdAndPluginsPluginId(tenantId, pluginDTO.getPluginId());
.map(Authentication::getPrincipal);
return Mono.zip(tenantMono, userObjectMono, (tenant, user) -> { return tenantMono
List<TenantPlugin> tenantPluginList = tenant.getPlugins(); .switchIfEmpty(Mono.defer(() -> {
if (tenantPluginList == null) { //If the plugin is not found in the tenant, its not already installed. Install now.
tenantPluginList = new ArrayList<TenantPlugin>(); return tenantService.findById(tenantId).map(tenant -> {
} List<TenantPlugin> tenantPluginList = tenant.getPlugins();
if (tenantPluginList == null) {
for (TenantPlugin listPlugin : tenantPluginList) { tenantPluginList = new ArrayList<TenantPlugin>();
if (listPlugin.getPlugin().getName().equals(plugin.getName())) { }
log.debug("Plugin {} is already installed for Tenant {}. Don't add again.", log.debug("Installing plugin {} for tenant {}", pluginDTO.getPluginId(), tenant.getName());
plugin.getName(), tenant.getName()); TenantPlugin tenantPlugin = new TenantPlugin();
return tenant; tenantPlugin.setPluginId(pluginDTO.getPluginId());
} tenantPlugin.setStatus(status);
} tenantPluginList.add(tenantPlugin);
TenantPlugin tenantPlugin = new TenantPlugin(); tenant.setPlugins(tenantPluginList);
//Set an ID in the nested document so that installed plugins can be referred to uniquely using IDs return tenant;
ObjectId objectId = new ObjectId(); }).flatMap(tenantService::save);
tenantPlugin.setId(objectId.toString()); }));
tenantPlugin.setPlugin(plugin);
tenantPlugin.setStatus(status);
tenantPluginList.add(tenantPlugin);
tenant.setPlugins(tenantPluginList);
return tenant;
}).flatMap(tenantService::save);
} }
public Mono<Plugin> findByName(String name) { public Mono<Plugin> findByName(String name) {
return repository.findByName(name); return repository.findByName(name);
} }
@Override
public Mono<Plugin> findById(String id) {
return repository.findById(id);
}
} }

View File

@ -4,5 +4,8 @@ import com.appsmith.server.domains.Resource;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
public interface ResourceService extends CrudService<Resource, String> { public interface ResourceService extends CrudService<Resource, String> {
Mono<Resource> findByName(String name); Mono<Resource> findByName(String name);
Mono<Resource> findById(String id);
} }

View File

@ -1,9 +1,7 @@
package com.appsmith.server.services; package com.appsmith.server.services;
import com.appsmith.server.domains.Plugin;
import com.appsmith.server.domains.Resource; import com.appsmith.server.domains.Resource;
import com.appsmith.server.domains.Tenant; import com.appsmith.server.domains.Tenant;
import com.appsmith.server.domains.TenantPlugin;
import com.appsmith.server.exceptions.AppsmithError; import com.appsmith.server.exceptions.AppsmithError;
import com.appsmith.server.exceptions.AppsmithException; import com.appsmith.server.exceptions.AppsmithException;
import com.appsmith.server.repositories.ResourceRepository; import com.appsmith.server.repositories.ResourceRepository;
@ -17,8 +15,6 @@ import reactor.core.publisher.Mono;
import reactor.core.scheduler.Scheduler; import reactor.core.scheduler.Scheduler;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
@Slf4j @Slf4j
@Service @Service
@ -43,36 +39,22 @@ public class ResourceServiceImpl extends BaseService<ResourceRepository, Resourc
public Mono<Resource> create(@NotNull Resource resource) throws AppsmithException { public Mono<Resource> create(@NotNull Resource resource) throws AppsmithException {
if (resource.getId() != null) { if (resource.getId() != null) {
throw new AppsmithException(AppsmithError.INVALID_PARAMETER, "id"); throw new AppsmithException(AppsmithError.INVALID_PARAMETER, "id");
} else if (resource.getPluginId() == null) {
throw new AppsmithException(AppsmithError.PLUGIN_ID_NOT_GIVEN);
} }
Mono<Tenant> tenantMono = tenantService.findById(tenantId); Mono<Tenant> tenantMono = tenantService.findByIdAndPluginsPluginId(tenantId, resource.getPluginId());
Mono<Plugin> pluginMono = pluginService.findByName(resource.getPlugin().getName());
Mono<Resource> updatedResourceMono = Mono.zip(tenantMono, pluginMono, (tenant, plugin) -> {
resource.setTenant(tenant);
resource.setPlugin(plugin);
return resource;
});
return updatedResourceMono //Add tenant id to the resource.
.filter(updatedResource -> { Mono<Resource> updatedResourceMono = Mono.just(resource)
AtomicReference<Boolean> temp = new AtomicReference<>(false); .map(updatedResource -> {
tenantMono.map(tenant -> { updatedResource.setTenantId(tenantId);
List<TenantPlugin> tenantPlugins = tenant.getPlugins(); return updatedResource;
if (tenantPlugins == null || tenantPlugins.isEmpty()) { });
temp.set(false);
return temp; return tenantMono
} .switchIfEmpty(Mono.error(new AppsmithException(AppsmithError.PLUGIN_NOT_INSTALLED, tenantId)))
for (TenantPlugin tenantPlugin : tenantPlugins) { .then(updatedResourceMono)
if (tenantPlugin.getPlugin().getName().equals(resource.getPlugin().getName())) {
temp.set(true);
return temp;
}
}
temp.set(false);
return temp;
}).block();
return temp.get();
})
.flatMap(repository::save); .flatMap(repository::save);
} }
@ -80,4 +62,9 @@ public class ResourceServiceImpl extends BaseService<ResourceRepository, Resourc
public Mono<Resource> findByName(String name) { public Mono<Resource> findByName(String name) {
return repository.findByName(name); return repository.findByName(name);
} }
@Override
public Mono<Resource> findById(String id) {
return repository.findById(id);
}
} }

View File

@ -12,4 +12,6 @@ public interface TenantService extends CrudService<Tenant, String> {
Mono<Tenant> findById(String id); Mono<Tenant> findById(String id);
Mono<Tenant> save(Tenant tenant); Mono<Tenant> save(Tenant tenant);
Mono<Tenant> findByIdAndPluginsPluginId(String tenantId, String pluginId);
} }

View File

@ -91,5 +91,10 @@ public class TenantServiceImpl extends BaseService<TenantRepository, Tenant, Str
return repository.save(tenant); return repository.save(tenant);
} }
@Override
public Mono<Tenant> findByIdAndPluginsPluginId(String tenantId, String pluginId) {
return repository.findByIdAndPluginsPluginId(tenantId, pluginId);
}
} }

View File

@ -6,6 +6,8 @@ import reactor.core.publisher.Mono;
public interface UserService extends CrudService<User, String> { public interface UserService extends CrudService<User, String> {
Mono<User> findByUsername(String name); Mono<User> findByUsername(String name);
Mono<User> findByEmail(String email); Mono<User> findByEmail(String email);
Mono<User> save(User newUser); Mono<User> save(User newUser);
} }