Removing manual FilePart type mapping
This commit is contained in:
parent
7857bd5000
commit
33c5f5f975
7 changed files with 80 additions and 15 deletions
|
@ -27,6 +27,7 @@ import org.mapstruct.Mapper;
|
||||||
import org.mapstruct.factory.Mappers;
|
import org.mapstruct.factory.Mappers;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.http.codec.multipart.FilePart;
|
import org.springframework.http.codec.multipart.FilePart;
|
||||||
|
import org.springframework.http.codec.multipart.Part;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
import org.springframework.web.server.ServerWebExchange;
|
import org.springframework.web.server.ServerWebExchange;
|
||||||
import reactor.core.publisher.Flux;
|
import reactor.core.publisher.Flux;
|
||||||
|
@ -92,16 +93,19 @@ public class ApplicationConfigController implements ApplicationConfigApi {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mono<ResponseEntity<UploadedFileInfoDTO>> uploadConfigRelatedFile(FilePart file, ServerWebExchange exchange) {
|
public Mono<ResponseEntity<UploadedFileInfoDTO>> uploadConfigRelatedFile(Flux<Part> fileFlux,
|
||||||
|
ServerWebExchange exchange) {
|
||||||
return accessControlService
|
return accessControlService
|
||||||
.validateAccess(
|
.validateAccess(
|
||||||
AccessContext.builder()
|
AccessContext.builder()
|
||||||
.applicationConfigActions(EDIT)
|
.applicationConfigActions(EDIT)
|
||||||
.build()
|
.build()
|
||||||
)
|
)
|
||||||
.then(dynamicConfigOperations.uploadConfigRelatedFile(file))
|
.then(fileFlux.single())
|
||||||
|
.flatMap(file ->
|
||||||
|
dynamicConfigOperations.uploadConfigRelatedFile((FilePart) file)
|
||||||
.map(path -> new UploadedFileInfoDTO().location(path.toString()))
|
.map(path -> new UploadedFileInfoDTO().location(path.toString()))
|
||||||
.map(ResponseEntity::ok);
|
.map(ResponseEntity::ok));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -90,6 +90,7 @@ public class DynamicConfigOperations {
|
||||||
}
|
}
|
||||||
|
|
||||||
public PropertiesStructure getCurrentProperties() {
|
public PropertiesStructure getCurrentProperties() {
|
||||||
|
checkIfDynamicConfigEnabled();
|
||||||
return PropertiesStructure.builder()
|
return PropertiesStructure.builder()
|
||||||
.kafka(getNullableBean(ClustersProperties.class))
|
.kafka(getNullableBean(ClustersProperties.class))
|
||||||
.rbac(getNullableBean(RoleBasedAccessControlProperties.class))
|
.rbac(getNullableBean(RoleBasedAccessControlProperties.class))
|
||||||
|
@ -112,11 +113,7 @@ public class DynamicConfigOperations {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void persist(PropertiesStructure properties) {
|
public void persist(PropertiesStructure properties) {
|
||||||
if (!dynamicConfigEnabled()) {
|
checkIfDynamicConfigEnabled();
|
||||||
throw new ValidationException(
|
|
||||||
"Dynamic config change is not allowed. "
|
|
||||||
+ "Set dynamic.config.enabled property to 'true' to enabled it.");
|
|
||||||
}
|
|
||||||
properties.initAndValidate();
|
properties.initAndValidate();
|
||||||
|
|
||||||
String yaml = serializeToYaml(properties);
|
String yaml = serializeToYaml(properties);
|
||||||
|
@ -124,8 +121,9 @@ public class DynamicConfigOperations {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Mono<Path> uploadConfigRelatedFile(FilePart file) {
|
public Mono<Path> uploadConfigRelatedFile(FilePart file) {
|
||||||
String targetDirStr = (String) ctx.getEnvironment().getSystemEnvironment()
|
checkIfDynamicConfigEnabled();
|
||||||
.getOrDefault(CONFIG_RELATED_UPLOADS_DIR_PROPERTY, CONFIG_RELATED_UPLOADS_DIR_DEFAULT);
|
String targetDirStr = ctx.getEnvironment()
|
||||||
|
.getProperty(CONFIG_RELATED_UPLOADS_DIR_PROPERTY, CONFIG_RELATED_UPLOADS_DIR_DEFAULT);
|
||||||
|
|
||||||
Path targetDir = Path.of(targetDirStr);
|
Path targetDir = Path.of(targetDirStr);
|
||||||
if (!Files.exists(targetDir)) {
|
if (!Files.exists(targetDir)) {
|
||||||
|
@ -149,6 +147,14 @@ public class DynamicConfigOperations {
|
||||||
.onErrorMap(th -> new FileUploadException(targetFilePath, th));
|
.onErrorMap(th -> new FileUploadException(targetFilePath, th));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void checkIfDynamicConfigEnabled(){
|
||||||
|
if (!dynamicConfigEnabled()) {
|
||||||
|
throw new ValidationException(
|
||||||
|
"Dynamic config change is not allowed. "
|
||||||
|
+ "Set dynamic.config.enabled property to 'true' to enabled it.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
private void writeYamlToFile(String yaml, Path path) {
|
private void writeYamlToFile(String yaml, Path path) {
|
||||||
if (Files.isDirectory(path)) {
|
if (Files.isDirectory(path)) {
|
||||||
|
|
|
@ -2,6 +2,7 @@ package com.provectus.kafka.ui;
|
||||||
|
|
||||||
import com.provectus.kafka.ui.container.KafkaConnectContainer;
|
import com.provectus.kafka.ui.container.KafkaConnectContainer;
|
||||||
import com.provectus.kafka.ui.container.SchemaRegistryContainer;
|
import com.provectus.kafka.ui.container.SchemaRegistryContainer;
|
||||||
|
import java.nio.file.Path;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import org.apache.kafka.clients.admin.AdminClient;
|
import org.apache.kafka.clients.admin.AdminClient;
|
||||||
|
@ -9,6 +10,7 @@ import org.apache.kafka.clients.admin.AdminClientConfig;
|
||||||
import org.apache.kafka.clients.admin.NewTopic;
|
import org.apache.kafka.clients.admin.NewTopic;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.junit.jupiter.api.function.ThrowingConsumer;
|
import org.junit.jupiter.api.function.ThrowingConsumer;
|
||||||
|
import org.junit.jupiter.api.io.TempDir;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient;
|
import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient;
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
@ -47,6 +49,9 @@ public abstract class AbstractIntegrationTest {
|
||||||
.dependsOn(kafka)
|
.dependsOn(kafka)
|
||||||
.dependsOn(schemaRegistry);
|
.dependsOn(schemaRegistry);
|
||||||
|
|
||||||
|
@TempDir
|
||||||
|
public static Path tmpDir;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
kafka.start();
|
kafka.start();
|
||||||
schemaRegistry.start();
|
schemaRegistry.start();
|
||||||
|
@ -76,6 +81,9 @@ public abstract class AbstractIntegrationTest {
|
||||||
System.setProperty("kafka.clusters.1.schemaRegistry", schemaRegistry.getUrl());
|
System.setProperty("kafka.clusters.1.schemaRegistry", schemaRegistry.getUrl());
|
||||||
System.setProperty("kafka.clusters.1.kafkaConnect.0.name", "kafka-connect");
|
System.setProperty("kafka.clusters.1.kafkaConnect.0.name", "kafka-connect");
|
||||||
System.setProperty("kafka.clusters.1.kafkaConnect.0.address", kafkaConnect.getTarget());
|
System.setProperty("kafka.clusters.1.kafkaConnect.0.address", kafkaConnect.getTarget());
|
||||||
|
|
||||||
|
System.setProperty("dynamic.config.enabled", "true");
|
||||||
|
System.setProperty("config.related.uploads.dir", tmpDir.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
package com.provectus.kafka.ui.controller;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
import com.provectus.kafka.ui.AbstractIntegrationTest;
|
||||||
|
import com.provectus.kafka.ui.model.UploadedFileInfoDTO;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.core.io.ClassPathResource;
|
||||||
|
import org.springframework.http.HttpEntity;
|
||||||
|
import org.springframework.http.client.MultipartBodyBuilder;
|
||||||
|
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||||
|
import org.springframework.util.MultiValueMap;
|
||||||
|
|
||||||
|
class ApplicationConfigControllerTest extends AbstractIntegrationTest {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private WebTestClient webTestClient;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpload() throws IOException {
|
||||||
|
var fileToUpload = new ClassPathResource("/fileForUploadTest.txt", this.getClass());
|
||||||
|
|
||||||
|
UploadedFileInfoDTO result = webTestClient
|
||||||
|
.post()
|
||||||
|
.uri("/api/config/relatedfiles")
|
||||||
|
.bodyValue(generateBody(fileToUpload))
|
||||||
|
.exchange()
|
||||||
|
.expectStatus()
|
||||||
|
.isOk()
|
||||||
|
.expectBody(UploadedFileInfoDTO.class)
|
||||||
|
.returnResult()
|
||||||
|
.getResponseBody();
|
||||||
|
|
||||||
|
assertThat(result).isNotNull();
|
||||||
|
assertThat(result.getLocation()).isNotNull();
|
||||||
|
assertThat(Path.of(result.getLocation()))
|
||||||
|
.hasSameBinaryContentAs(fileToUpload.getFile().toPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
private MultiValueMap<String, HttpEntity<?>> generateBody(ClassPathResource resource) {
|
||||||
|
MultipartBodyBuilder builder = new MultipartBodyBuilder();
|
||||||
|
builder.part("file", resource);
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
1
kafka-ui-api/src/test/resources/fileForUploadTest.txt
Normal file
1
kafka-ui-api/src/test/resources/fileForUploadTest.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
some content goes here
|
|
@ -101,9 +101,6 @@
|
||||||
<useSpringBoot3>true</useSpringBoot3>
|
<useSpringBoot3>true</useSpringBoot3>
|
||||||
<dateLibrary>java8</dateLibrary>
|
<dateLibrary>java8</dateLibrary>
|
||||||
</configOptions>
|
</configOptions>
|
||||||
<typeMappings>
|
|
||||||
<mapping>filepart=org.springframework.http.codec.multipart.FilePart</mapping>
|
|
||||||
</typeMappings>
|
|
||||||
</configuration>
|
</configuration>
|
||||||
</execution>
|
</execution>
|
||||||
<execution>
|
<execution>
|
||||||
|
|
|
@ -1819,7 +1819,7 @@ paths:
|
||||||
properties:
|
properties:
|
||||||
file:
|
file:
|
||||||
type: string
|
type: string
|
||||||
format: filepart
|
format: binary
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
description: OK
|
description: OK
|
||||||
|
|
Loading…
Add table
Reference in a new issue