Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,9 @@ public interface ImportServiceCE {
ArtifactBasedImportService<? extends Artifact, ? extends ArtifactImportDTO, ? extends ArtifactExchangeJson>
getArtifactBasedImportService(ArtifactType artifactType);

/**
* This method takes a file part and makes a Json entity which implements the ArtifactExchangeJson interface
*
* @param filePart : filePart from which the contents would be made
* @return : Json entity which implements ArtifactExchangeJson
*/
Mono<? extends ArtifactExchangeJson> extractArtifactExchangeJson(Part filePart);
Mono<String> readFilePartToString(Part file);

Mono<? extends ArtifactExchangeJson> extractArtifactExchangeJson(String jsonString);

/**
* Hydrates an Artifact within the specified workspace by saving the provided JSON file.
Expand All @@ -50,6 +46,17 @@ public interface ImportServiceCE {
Mono<? extends ArtifactImportDTO> extractArtifactExchangeJsonAndSaveArtifact(
Part filePart, String workspaceId, String artifactId);

/**
* Hydrates an Artifact within the specified workspace by saving the provided JSON file.
*
* @param jsonContents The JSON representing the Artifact object to be saved.
* The Artifact implements the Artifact interface.
* @param workspaceId The identifier for the destination workspace.
* @param artifactId
*/
Mono<? extends ArtifactImportDTO> extractArtifactExchangeJsonAndSaveArtifact(
String jsonContents, String workspaceId, String artifactId);

/**
* Saves the provided ArtifactExchangeJson within the specified workspace.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,50 +100,61 @@ public class ImportServiceCEImpl implements ImportServiceCE {
};
}

/**
* This method takes a file part and makes a Json entity which implements the ArtifactExchangeJson interface
*
* @param filePart : filePart from which the contents would be made
* @return : Json entity which implements ArtifactExchangeJson
*/
public Mono<? extends ArtifactExchangeJson> extractArtifactExchangeJson(Part filePart) {

final MediaType contentType = filePart.headers().getContentType();
@Override
public Mono<String> readFilePartToString(Part file) {
final MediaType contentType = file.headers().getContentType();
if (contentType == null || !ALLOWED_CONTENT_TYPES.contains(contentType)) {
log.error("Invalid content type, {}", contentType);
return Mono.error(new AppsmithException(AppsmithError.VALIDATION_FAILURE, INVALID_JSON_FILE));
}

return DataBufferUtils.join(filePart.content())
.map(dataBuffer -> {
byte[] data = new byte[dataBuffer.readableByteCount()];
dataBuffer.read(data);
DataBufferUtils.release(dataBuffer);
return new String(data);
})
.map(jsonString -> {
gsonBuilder.registerTypeAdapter(ArtifactExchangeJson.class, artifactExchangeJsonAdapter);
Gson gson = gsonBuilder.create();
return gson.fromJson(jsonString, ArtifactExchangeJson.class);
});
return DataBufferUtils.join(file.content()).map(dataBuffer -> {
byte[] data = new byte[dataBuffer.readableByteCount()];
dataBuffer.read(data);
DataBufferUtils.release(dataBuffer);
return new String(data);
});
}

/**
* This method takes JSON content and makes a JSON entity which implements the ArtifactExchangeJson interface.
*
* @param jsonString JSON string to parse
* @return JSON entity which implements ArtifactExchangeJson
*/
@Override
public Mono<? extends ArtifactExchangeJson> extractArtifactExchangeJson(String jsonString) {
return Mono.fromCallable(() -> {
gsonBuilder.registerTypeAdapter(ArtifactExchangeJson.class, artifactExchangeJsonAdapter);
Gson gson = gsonBuilder.create();
return gson.fromJson(jsonString, ArtifactExchangeJson.class);
});
}

@Override
public Mono<? extends ArtifactImportDTO> extractArtifactExchangeJsonAndSaveArtifact(
Part filePart, String workspaceId, String artifactId) {
return readFilePartToString(filePart)
.flatMap(jsonContents ->
extractArtifactExchangeJsonAndSaveArtifact(jsonContents, workspaceId, artifactId));
}

/**
* Hydrates an Artifact within the specified workspace by saving the provided JSON file.
*
* @param filePart The filePart representing the Artifact object to be saved.
* @param jsonContents The jsonContents representing the Artifact object to be saved.
* The Artifact implements the Artifact interface.
* @param workspaceId The identifier for the destination workspace.
*/
@Override
public Mono<? extends ArtifactImportDTO> extractArtifactExchangeJsonAndSaveArtifact(
Part filePart, String workspaceId, String artifactId) {
String jsonContents, String workspaceId, String artifactId) {

if (StringUtils.isEmpty(workspaceId)) {
return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, FieldName.WORKSPACE_ID));
}

Mono<ArtifactImportDTO> importedContextMono = extractArtifactExchangeJson(filePart)
Mono<ArtifactImportDTO> importedContextMono = extractArtifactExchangeJson(jsonContents)
.zipWhen(contextJson -> {
if (StringUtils.isEmpty(artifactId)) {
return importNewArtifactInWorkspaceFromJson(workspaceId, contextJson);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,8 @@ public interface PartialImportServiceCE {

Mono<Application> importResourceInPage(String workspaceId, String applicationId, String pageId, Part file);

Mono<Application> importResourceInPage(
String workspaceId, String applicationId, String pageId, String fileContents);

Mono<BuildingBlockResponseDTO> importBuildingBlock(BuildingBlockDTO buildingBlockDTO);
}
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,17 @@ public class PartialImportServiceCEImpl implements PartialImportServiceCE {

@Override
public Mono<Application> importResourceInPage(String workspaceId, String applicationId, String pageId, Part file) {
return importService
.readFilePartToString(file)
.flatMap(fileContents -> importResourceInPage(workspaceId, applicationId, pageId, fileContents));
}

@Override
public Mono<Application> importResourceInPage(
String workspaceId, String applicationId, String pageId, String fileContents) {
Mono<User> currUserMono = sessionUserService.getCurrentUser();
return importService
.extractArtifactExchangeJson(file)
.extractArtifactExchangeJson(fileContents)
.flatMap(artifactExchangeJson -> {
if (artifactExchangeJson instanceof ApplicationJson
&& isImportableResource((ApplicationJson) artifactExchangeJson)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.MediaType;
import org.springframework.http.client.MultipartBodyBuilder;
import org.springframework.http.codec.multipart.Part;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.web.reactive.server.WebTestClient;
import org.springframework.web.reactive.function.BodyInserters;
Expand All @@ -29,6 +30,7 @@
import java.io.IOException;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;

@SpringBootTest
@AutoConfigureWebTestClient
Expand Down Expand Up @@ -69,7 +71,7 @@ private MultipartBodyBuilder createBodyBuilder(String fileName) throws IOExcepti
@WithMockUser
public void whenFileUploadedWithLongHeader_thenVerifyErrorStatus() throws IOException {

Mockito.when(importService.extractArtifactExchangeJsonAndSaveArtifact(any(), any(), any()))
Mockito.when(importService.extractArtifactExchangeJsonAndSaveArtifact(anyString(), any(), any()))
.thenAnswer(importableArtifactDTOAnswer(new ApplicationImportDTO()));

final String fileName = getFileName(130 * 1024);
Expand Down Expand Up @@ -100,7 +102,7 @@ public void whenFileUploadedWithLongHeader_thenVerifyErrorStatus() throws IOExce
@WithMockUser
public void whenFileUploadedWithShortHeader_thenVerifySuccessStatus() throws IOException {

Mockito.when(importService.extractArtifactExchangeJsonAndSaveArtifact(any(), any(), any()))
Mockito.when(importService.extractArtifactExchangeJsonAndSaveArtifact(any(Part.class), any(), any()))
.thenAnswer(importableArtifactDTOAnswer(new ApplicationImportDTO()));

final String fileName = getFileName(2 * 1024);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
Expand All @@ -41,20 +42,16 @@
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.boot.test.mock.mockito.SpyBean;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.http.MediaType;
import org.springframework.http.codec.multipart.FilePart;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.security.test.context.support.WithUserDetails;
import org.springframework.test.annotation.DirtiesContext;
import reactor.core.publisher.Flux;
import org.springframework.util.StreamUtils;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;

import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Instant;
Expand Down Expand Up @@ -228,13 +225,13 @@ public void verifyAssertions(
@WithUserDetails(value = "api_user")
public void importApplication_ThenExportApplication_MatchJson_equals_Success() throws URISyntaxException {
String filePath = "ce-automation-test.json";
FilePart filePart = createFilePart(filePath);
String jsonContents = readResource(filePath);
Workspace newWorkspace = new Workspace();
newWorkspace.setName("Template Workspace");
Mono<Workspace> workspaceMono = workspaceService.create(newWorkspace).cache();

ApplicationJson applicationJsonToBeImported = importService
.extractArtifactExchangeJson(filePart)
.extractArtifactExchangeJson(jsonContents)
.map(artifactExchangeJson -> (ApplicationJson) artifactExchangeJson)
.block();

Expand All @@ -249,7 +246,7 @@ public void importApplication_ThenExportApplication_MatchJson_equals_Success() t

final Mono<ApplicationImportDTO> resultMono = workspaceMono
.flatMap(workspace ->
importService.extractArtifactExchangeJsonAndSaveArtifact(filePart, workspace.getId(), null))
importService.extractArtifactExchangeJsonAndSaveArtifact(jsonContents, workspace.getId(), null))
.map(importableArtifactDTO -> (ApplicationImportDTO) importableArtifactDTO);

final Mono<ApplicationJson> exportApplicationMono = resultMono.flatMap(applicationImportDTO -> {
Expand Down Expand Up @@ -280,17 +277,10 @@ public void importApplication_ThenExportApplication_MatchJson_equals_Success() t
.verifyComplete();
}

private FilePart createFilePart(String filePath) throws URISyntaxException {
FilePart filePart = Mockito.mock(FilePart.class, Mockito.RETURNS_DEEP_STUBS);
URL resource = this.getClass().getResource(filePath);
Flux<DataBuffer> dataBufferFlux = DataBufferUtils.read(
Path.of(resource.toURI()), new DefaultDataBufferFactory(), 4096)
.cache();

Mockito.when(filePart.content()).thenReturn(dataBufferFlux);
Mockito.when(filePart.headers().getContentType()).thenReturn(MediaType.APPLICATION_JSON);

return filePart;
@SneakyThrows
private String readResource(String filePath) {
return StreamUtils.copyToString(
new DefaultResourceLoader().getResource(filePath).getInputStream(), StandardCharsets.UTF_8);
}

private void removeCustomJsLibsEntries(JsonObject applicationObjectNode) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import net.minidev.json.JSONArray;
import net.minidev.json.JSONObject;
Expand All @@ -93,6 +94,7 @@
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.boot.test.mock.mockito.SpyBean;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
Expand All @@ -102,6 +104,7 @@
import org.springframework.security.test.context.support.WithUserDetails;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.StreamUtils;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
Expand All @@ -110,6 +113,7 @@

import java.net.URISyntaxException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.time.Duration;
import java.time.Instant;
Expand Down Expand Up @@ -859,10 +863,8 @@ public void importArtifactFromInvalidFileTest() {
@Test
@WithUserDetails(value = "api_user")
public void importArtifactWithNullWorkspaceIdTest() {
FilePart filepart = Mockito.mock(FilePart.class, Mockito.RETURNS_DEEP_STUBS);

Mono<? extends ArtifactImportDTO> resultMono =
importService.extractArtifactExchangeJsonAndSaveArtifact(filepart, null, null);
importService.extractArtifactExchangeJsonAndSaveArtifact("", null, null);

StepVerifier.create(resultMono)
.expectErrorMatches(throwable -> throwable instanceof AppsmithException
Expand Down Expand Up @@ -4943,9 +4945,10 @@ public void mergeApplicationJsonWithApplication_WhenNoPermissionToCreatePage_Fai
return applicationRepository.save(application);
})
.flatMap(application -> {
FilePart filePart = createFilePart("test_assets/ImportExportServiceTest/valid-application.json");
final String validAppJsonContents =
readResource("test_assets/ImportExportServiceTest/valid-application.json");
return importService
.extractArtifactExchangeJson(filePart)
.extractArtifactExchangeJson(validAppJsonContents)
.map(artifactExchangeJson -> (ApplicationJson) artifactExchangeJson)
.flatMap(applicationJson -> importService.mergeArtifactExchangeJsonWithImportableArtifact(
workspaceId, application.getId(), null, applicationJson, null))
Expand All @@ -4957,6 +4960,12 @@ public void mergeApplicationJsonWithApplication_WhenNoPermissionToCreatePage_Fai
.verify();
}

@SneakyThrows
private String readResource(String filePath) {
return StreamUtils.copyToString(
new DefaultResourceLoader().getResource(filePath).getInputStream(), StandardCharsets.UTF_8);
}

@Test
@WithUserDetails(value = "api_user")
public void extractFileAndUpdateNonGitConnectedApplication_WhenNoPermissionToCreatePage_Fails() {
Expand Down
Loading
Loading