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.User;
import com.appsmith.server.domains.UserState;
import com.appsmith.server.services.UserService;
import com.appsmith.server.services.TenantService;
import com.appsmith.server.services.UserService;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;

View File

@ -1,9 +1,9 @@
package com.appsmith.server.configurations;
import com.appsmith.server.services.UserService;
import com.appsmith.server.constants.Security;
import com.appsmith.server.services.TenantService;
import com.appsmith.server.services.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
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.dtos.ResponseDto;
import com.appsmith.server.services.CrudService;
import com.appsmith.server.exceptions.AppsmithException;
import com.appsmith.server.services.CrudService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
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.Mono;

View File

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

View File

@ -1,14 +1,18 @@
package com.appsmith.server.controllers;
import com.appsmith.server.constants.Url;
import com.appsmith.server.domains.Plugin;
import com.appsmith.server.domains.Tenant;
import com.appsmith.server.dtos.PluginTenantDTO;
import com.appsmith.server.dtos.ResponseDto;
import com.appsmith.server.services.PluginService;
import com.appsmith.server.constants.Url;
import org.springframework.beans.factory.annotation.Autowired;
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 javax.validation.Valid;

View File

@ -1,11 +1,15 @@
package com.appsmith.server.controllers;
import com.appsmith.server.constants.Url;
import com.appsmith.server.domains.Query;
import com.appsmith.server.dtos.CommandQueryParams;
import com.appsmith.server.services.QueryService;
import com.appsmith.server.constants.Url;
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;
@RestController

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -3,7 +3,11 @@ package com.appsmith.server.domains;
import lombok.Getter;
import lombok.Setter;
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 java.util.Date;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,10 @@
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;

View File

@ -9,6 +9,9 @@ public enum AppsmithError {
NO_RESOURCE_FOUND(404, 1000, "Unable to find {0} with id {1}"),
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");
private Integer httpErrorCode;

View File

@ -1,6 +1,7 @@
package com.appsmith.server.exceptions;
import com.appsmith.server.dtos.ResponseDto;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
@ -13,20 +14,23 @@ import reactor.core.publisher.Mono;
* sending it to the client.
*/
@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
/**
* 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
* 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
* @return Mono<ResponseDto<ErrorDTO>>
* @return Mono<ResponseDto < ErrorDTO>>
*/
@ExceptionHandler
@ResponseBody
public Mono<ResponseDto<ErrorDTO>> catchAppsmithException(AppsmithException e, ServerWebExchange exchange) {
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));
}
@ -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
* 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
* @return Mono<ResponseDto<ErrorDTO>>
* @return Mono<ResponseDto < ErrorDTO>>
*/
@ExceptionHandler
@ResponseBody
public Mono<ResponseDto<ErrorDTO>> catchException(Exception e, ServerWebExchange exchange) {
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(),
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) {
return Mono.subscriberContext().doOnNext(ctx -> {
if(!ctx.hasKey(LogHelper.CONTEXT_MAP)) {
if (!ctx.hasKey(LogHelper.CONTEXT_MAP)) {
return;
}
@ -67,12 +67,12 @@ public class MDCFilter implements WebFilter {
// Add all the request MDC keys to the response object
ctx.<Map<String, String>>get(LogHelper.CONTEXT_MAP)
.forEach((key, value) -> {
if(!key.contains(REQUEST_ID_LOG)) {
if (!key.contains(REQUEST_ID_LOG)) {
httpHeaders.add(MDC_HEADER_PREFIX + key, value);
} else {
httpHeaders.add(REQUEST_ID_HEADER, value);
}
});
});
}).then();
}

View File

@ -1,14 +1,19 @@
package com.appsmith.server.plugins;
import com.appsmith.server.services.PluginExecutor;
import com.appsmith.server.domains.Query;
import com.appsmith.server.dtos.CommandQueryParams;
import com.appsmith.server.services.PluginExecutor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
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.HashMap;

View File

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

View File

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

View File

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

View File

@ -7,4 +7,6 @@ import reactor.core.publisher.Mono;
@Repository
public interface TenantRepository extends BaseRepository<Tenant, String> {
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> {
Mono<User> findByName(String name);
Mono<User> findByEmail(String email);
}

View File

@ -1,7 +1,9 @@
package com.appsmith.server.services;
import com.appsmith.server.domains.Action;
import com.appsmith.server.domains.Plugin;
import com.appsmith.server.domains.Resource;
import com.appsmith.server.exceptions.AppsmithError;
import com.appsmith.server.exceptions.AppsmithException;
import com.appsmith.server.repositories.ActionRepository;
import lombok.extern.slf4j.Slf4j;
@ -20,25 +22,32 @@ public class ActionServiceImpl extends BaseService<ActionRepository, Action, Str
private final ActionRepository repository;
private final ResourceService resourceService;
private final PluginService pluginService;
@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);
this.repository = repository;
this.resourceService = resourceService;
this.pluginService = pluginService;
}
@Override
public Mono<Action> create(@NotNull Action action) throws AppsmithException {
if (action.getId() != null) {
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 -> {
action.setResource(resource);
return pluginMono
//Set plugin in the action before saving.
.map(plugin -> {
action.setPluginId(plugin.getId());
return action;
})
.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.AppsmithException;
import com.appsmith.server.repositories.BaseRepository;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import org.springframework.data.mongodb.core.ReactiveMongoTemplate;

View File

@ -1,11 +1,11 @@
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.dtos.CommandQueryParams;
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 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.Tenant;
import com.appsmith.server.dtos.PluginTenantDTO;
import com.appsmith.server.exceptions.AppsmithException;
import reactor.core.publisher.Mono;
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> 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.UserRepository;
import lombok.extern.slf4j.Slf4j;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.data.mongodb.core.ReactiveMongoTemplate;
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 reactor.core.publisher.Mono;
import reactor.core.scheduler.Scheduler;
@ -80,14 +76,17 @@ public class PluginServiceImpl extends BaseService<PluginRepository, Plugin, Str
@Override
public Mono<Tenant> installPlugin(PluginTenantDTO pluginTenantDTO) {
return pluginRepository
.findByName(pluginTenantDTO.getName())
.flatMap(plugin1 -> storeTenantPlugin(plugin1, pluginTenantDTO.getStatus()))
if (pluginTenantDTO.getPluginId() == null) {
return Mono.error(new AppsmithException(AppsmithError.PLUGIN_ID_NOT_GIVEN));
}
return Mono.just(pluginTenantDTO)
.flatMap(plugin -> storeTenantPlugin(plugin, pluginTenantDTO.getStatus()))
.switchIfEmpty(Mono.empty());
}
@Override
public Mono<Tenant> uninstallPlugin(PluginTenantDTO plugin) {
public Mono<Tenant> uninstallPlugin(PluginTenantDTO pluginDTO) {
/*TODO
* Tenant & user association is being mocked here by forcefully
* 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
* 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
.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 -> {
List<TenantPlugin> tenantPluginList = tenant.getPlugins();
if (tenantPluginList == null || tenantPluginList.isEmpty()) {
return tenant;
}
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());
tenantPluginList.removeIf(listPlugin -> listPlugin.getPluginId().equals(pluginDTO.getPluginId()));
tenant.setPlugins(tenantPluginList);
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);
}
private Mono<Tenant> storeTenantPlugin(Plugin plugin, TenantPluginStatus status) {
private Mono<Tenant> storeTenantPlugin(PluginTenantDTO pluginDTO, TenantPluginStatus status) {
/*TODO
* Tenant & user association is being mocked here by forcefully
* 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);
* 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
* 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()
.map(SecurityContext::getAuthentication)
.map(Authentication::getPrincipal);
//Find the tenant using id and plugin id -> This is to find if the tenant already has the plugin installed
Mono<Tenant> tenantMono = tenantService.findByIdAndPluginsPluginId(tenantId, pluginDTO.getPluginId());
return Mono.zip(tenantMono, userObjectMono, (tenant, user) -> {
List<TenantPlugin> tenantPluginList = tenant.getPlugins();
if (tenantPluginList == null) {
tenantPluginList = new ArrayList<TenantPlugin>();
}
for (TenantPlugin listPlugin : tenantPluginList) {
if (listPlugin.getPlugin().getName().equals(plugin.getName())) {
log.debug("Plugin {} is already installed for Tenant {}. Don't add again.",
plugin.getName(), tenant.getName());
return tenant;
}
}
TenantPlugin tenantPlugin = new TenantPlugin();
//Set an ID in the nested document so that installed plugins can be referred to uniquely using IDs
ObjectId objectId = new ObjectId();
tenantPlugin.setId(objectId.toString());
tenantPlugin.setPlugin(plugin);
tenantPlugin.setStatus(status);
tenantPluginList.add(tenantPlugin);
tenant.setPlugins(tenantPluginList);
return tenant;
}).flatMap(tenantService::save);
return tenantMono
.switchIfEmpty(Mono.defer(() -> {
//If the plugin is not found in the tenant, its not already installed. Install now.
return tenantService.findById(tenantId).map(tenant -> {
List<TenantPlugin> tenantPluginList = tenant.getPlugins();
if (tenantPluginList == null) {
tenantPluginList = new ArrayList<TenantPlugin>();
}
log.debug("Installing plugin {} for tenant {}", pluginDTO.getPluginId(), tenant.getName());
TenantPlugin tenantPlugin = new TenantPlugin();
tenantPlugin.setPluginId(pluginDTO.getPluginId());
tenantPlugin.setStatus(status);
tenantPluginList.add(tenantPlugin);
tenant.setPlugins(tenantPluginList);
return tenant;
}).flatMap(tenantService::save);
}));
}
public Mono<Plugin> findByName(String 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;
public interface ResourceService extends CrudService<Resource, String> {
Mono<Resource> findByName(String name);
Mono<Resource> findById(String id);
}

View File

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