Skip to content

Commit

Permalink
fetch and update flow yaml
Browse files Browse the repository at this point in the history
  • Loading branch information
gy2006 committed Dec 21, 2024
1 parent e6c5c54 commit f4c7f9c
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 26 deletions.
8 changes: 6 additions & 2 deletions src/main/java/com/flowci/common/config/AppConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.nio.charset.StandardCharsets;
import java.util.List;

@Configuration
Expand All @@ -42,12 +43,15 @@ public void addCorsMappings(CorsRegistry registry) {
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.clear();

var jacksonConverter = new MappingJackson2HttpMessageConverter(ObjectMapperFactory.instance());
jacksonConverter.setDefaultCharset(StandardCharsets.UTF_8);

converters.addAll(List.of(
new ByteArrayHttpMessageConverter(),
new MappingJackson2HttpMessageConverter(ObjectMapperFactory.instance()),
jacksonConverter,
new ResourceHttpMessageConverter(),
new AllEncompassingFormHttpMessageConverter(),
new StringHttpMessageConverter()
new StringHttpMessageConverter(StandardCharsets.UTF_8)
));
}
};
Expand Down
74 changes: 56 additions & 18 deletions src/main/java/com/flowci/flow/FlowController.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,22 @@
import com.flowci.common.exception.DuplicateException;
import com.flowci.common.exception.ExceptionUtils;
import com.flowci.common.validator.ValidId;
import com.flowci.flow.business.CreateFlow;
import com.flowci.flow.business.FetchFlow;
import com.flowci.flow.business.FetchTemplates;
import com.flowci.flow.business.ListFlows;
import com.flowci.flow.business.*;
import com.flowci.flow.model.CreateFlowParam;
import com.flowci.flow.model.Flow;
import com.flowci.flow.model.YamlTemplate;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.ExampleObject;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Min;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.PageRequest;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;

import java.util.List;
Expand All @@ -30,12 +33,11 @@
public class FlowController {

private final FetchTemplates fetchTemplates;

private final CreateFlow createFlow;

private final ListFlows listFlows;

private final FetchFlow fetchFlow;
private final FetchFlowYamlContent fetchFlowYamlContent;
private final UpdateFlowYamlContent updateFlowYamlContent;

@GetMapping("/{id}")
public Flow getFlow(@PathVariable("id") @Valid @ValidId String id) {
Expand All @@ -44,24 +46,19 @@ public Flow getFlow(@PathVariable("id") @Valid @ValidId String id) {

@GetMapping
public List<Flow> getFlows(@RequestParam(required = false, name = "parentId", defaultValue = "10000")
@Valid
@ValidId String parentId,
@Valid @ValidId
String parentId,

@RequestParam(required = false, name = "page", defaultValue = "0")
@Valid
@Min(0) Integer page,
@Valid @Min(0)
Integer page,

@RequestParam(required = false, name = "size", defaultValue = "20")
@Valid
@Min(20) Integer size) {
@Valid @Min(20)
Integer size) {
return listFlows.invoke(parseLong(parentId), PageRequest.of(page, size));
}

@GetMapping("/templates")
public List<YamlTemplate> getTemplates() {
return fetchTemplates.invoke();
}

@PostMapping
public Flow createFlow(@RequestBody @Valid CreateFlowParam param) {
try {
Expand All @@ -73,4 +70,45 @@ public Flow createFlow(@RequestBody @Valid CreateFlowParam param) {
);
}
}

@GetMapping("/templates")
public List<YamlTemplate> getTemplates() {
return fetchTemplates.invoke();
}

@Operation(
description = "fetch flow yaml return base64 encoded yaml content",
parameters = @Parameter(name = "id", description = "flow id"),
responses = @ApiResponse(
description = "base64 encoded yaml",
content = @Content(
examples = @ExampleObject(value = "c3RlcHM6CiAgLSBuYW1lOiBzdGVwXzE" +
"KICAgIGNvbW1hbmRzOgogICAgICAtIG5hbWU6IHByaW50CiAgICAgICAgYmFz" +
"aDogfAogICAgICAgICAgZWNobyAic3RlcCAxIG9uIGJhc2gi")
)
)
)
@GetMapping(value = "/{id}/yaml", produces = MediaType.TEXT_PLAIN_VALUE)
public String getYaml(@PathVariable("id") @Valid @ValidId String id) {
return fetchFlowYamlContent.invoke(parseLong(id));
}

@Operation(
description = "update yaml by flow id",
parameters = @Parameter(name = "id", description = "flow id"),
requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(
description = "base64 encoded yaml",
required = true,
content = @Content(
examples = @ExampleObject(value = "c3RlcHM6CiAgLSBuYW1lOiBzdGVwXzE" +
"KICAgIGNvbW1hbmRzOgogICAgICAtIG5hbWU6IHByaW50CiAgICAgICAgYmFz" +
"aDogfAogICAgICAgICAgZWNobyAic3RlcCAxIG9uIGJhc2gi")
)
)
)
@PostMapping(value = "/{id}/yaml", consumes = MediaType.TEXT_PLAIN_VALUE)
public void updateYaml(@PathVariable("id") @Valid @ValidId String id,
@RequestBody String b64Yaml) {
updateFlowYamlContent.invoke(parseLong(id), b64Yaml);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ private Flow toObject(CreateFlowParam param) {
flow.setName(param.name());
flow.setType(Flow.Type.FLOW);
flow.setVariables(Variables.EMPTY);
flow.setParentId(param.rootId() == null ? Flow.ROOT_ID : param.rootId());
flow.setParentId(param.parent() == null ? Flow.ROOT_ID : param.parent());
flow.setCreatedBy(requestContextHolder.getUserId());
flow.setUpdatedBy(requestContextHolder.getUserId());
return flow;
Expand Down
20 changes: 17 additions & 3 deletions src/main/java/com/flowci/flow/model/CreateFlowParam.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,28 @@
package com.flowci.flow.model;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.flowci.common.validator.ValidName;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.annotation.Nullable;

public record CreateFlowParam(@ValidName(message = "invalid flow name") String name,
@Nullable String template,
@Nullable Long rootId) {
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.NOT_REQUIRED;
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;

public record CreateFlowParam(@ValidName(message = "invalid flow name")
@Schema(description = "flow name", example = "hello_world", requiredMode = REQUIRED)
String name,

@Nullable
@Schema(description = "template name", example = "maven", requiredMode = NOT_REQUIRED)
String template,

@Nullable
@Schema(description = "parent flow id", example = "110011", requiredMode = NOT_REQUIRED)
Long parent) {

private static final String BLANK_TEMPLATE = "_blank_";

@JsonIgnore
public boolean isBlank() {
return template == null || BLANK_TEMPLATE.equals(template);
}
Expand Down
45 changes: 43 additions & 2 deletions src/test/java/com/flowci/flow/FlowControllerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,28 @@
import com.flowci.common.model.ErrorResponse;
import com.flowci.flow.business.CreateFlow;
import com.flowci.flow.business.FetchFlow;
import com.flowci.flow.business.FetchFlowYamlContent;
import com.flowci.flow.business.UpdateFlowYamlContent;
import com.flowci.flow.model.CreateFlowParam;
import com.flowci.flow.model.Flow;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;

import java.sql.SQLException;
import java.util.Base64;

import static com.flowci.TestUtils.newDummyInstance;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

class FlowControllerTest extends SpringTest {
Expand All @@ -39,6 +43,12 @@ class FlowControllerTest extends SpringTest {
@MockBean
private FetchFlow fetchFlow;

@MockBean
private FetchFlowYamlContent fetchFlowYamlContent;

@MockBean
private UpdateFlowYamlContent updateFlowYamlContent;

@Test
void givenCreateFlowParameter_whenCreateFlow_thenReturnFlowId() throws Exception {
var expectedFlow = new Flow();
Expand Down Expand Up @@ -135,4 +145,35 @@ void givenInvalidFlowId_whenFetching_thenReturnError() throws Exception {
assertEquals(400, error.code());
assertEquals("invalid id", error.message());
}

@Test
void givenFlowId_whenFetchingYaml_thenReturnBase64EncodedYaml() throws Exception {
var expectedYaml = Base64.getEncoder().encodeToString("some yaml".getBytes());
when(fetchFlowYamlContent.invoke(any())).thenReturn(expectedYaml);

var r = mvc.perform(get("/v2/flows/1001/yaml"))
.andExpectAll(
status().is2xxSuccessful(),
header().string("Content-Type", "text/plain;charset=UTF-8")
)
.andReturn();

assertEquals(expectedYaml, r.getResponse().getContentAsString());
}

@Test
void givenFlowIdAndYaml_whenUpdating_thenYamlIsUpdated() throws Exception {
var expectedYaml = Base64.getEncoder().encodeToString("some yaml".getBytes());

var yamlCaptor = ArgumentCaptor.forClass(String.class);
doNothing().when(updateFlowYamlContent).invoke(any(), yamlCaptor.capture());

var r = mvc.perform(post("/v2/flows/1001/yaml")
.contentType(MediaType.TEXT_PLAIN)
.content(expectedYaml))
.andExpect(status().is2xxSuccessful())
.andReturn();

assertEquals(expectedYaml, yamlCaptor.getValue());
}
}

0 comments on commit f4c7f9c

Please sign in to comment.