FINERACT-2246: New command processing - document management

This commit is contained in:
Aleksandar Vidakovic
2026-02-16 14:56:40 +01:00
committed by Aleksandar Vidakovic
parent 8a61e30a45
commit 2ff0c62f40
172 changed files with 5928 additions and 3100 deletions
@@ -0,0 +1,44 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.infrastructure;
import static org.apache.fineract.infrastructure.contentstore.processor.ContentProcessor.BEAN_NAME_EXECUTOR;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.apache.fineract.infrastructure.core.config.FineractProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
@Configuration
@EnableConfigurationProperties({ FineractProperties.class })
@PropertySource("classpath:application-test.properties")
@ComponentScan({ "org.apache.fineract.infrastructure.contentstore.util", "org.apache.fineract.infrastructure.contentstore.detector",
"org.apache.fineract.infrastructure.contentstore.processor", "org.apache.fineract.infrastructure.contentstore.policy",
"org.apache.fineract.infrastructure.contentstore.service" })
public class TestConfiguration {
@Bean(BEAN_NAME_EXECUTOR)
public ExecutorService contentProcessorExecutor() {
return Executors.newCachedThreadPool();
}
}
@@ -0,0 +1,52 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.infrastructure.contentstore.detector;
import static org.junit.jupiter.api.Assertions.assertEquals;
import lombok.extern.slf4j.Slf4j;
import org.apache.fineract.infrastructure.TestConfiguration;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ContextConfiguration;
@Slf4j
@SpringBootTest
@ContextConfiguration(classes = TestConfiguration.class)
class FileContentDetectorTest {
@Autowired
private FileContentDetector fileContentDetector;
@Test
void detectByFileName() {
var ctx = fileContentDetector.detect(ContentDetectorContext.builder().fileName("test.png").build());
assertEquals("png", ctx.getFormat());
assertEquals(".png", ctx.getExtension());
assertEquals("image/png", ctx.getMimeType());
ctx = fileContentDetector.detect(ContentDetectorContext.builder().fileName("test.jpg").build());
assertEquals("jpg", ctx.getFormat());
assertEquals(".jpg", ctx.getExtension());
assertEquals("image/jpeg", ctx.getMimeType());
}
}
@@ -0,0 +1,134 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.infrastructure.contentstore.detector;
import static com.github.romankh3.image.comparison.model.ImageComparisonState.MATCH;
import static java.util.Objects.requireNonNull;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import com.github.romankh3.image.comparison.ImageComparison;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import javax.imageio.ImageIO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.fineract.infrastructure.TestConfiguration;
import org.apache.fineract.infrastructure.contentstore.exception.ContentDetectorException;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ContextConfiguration;
@Slf4j
@SpringBootTest
@ContextConfiguration(classes = TestConfiguration.class)
class TikaContentDetectorTest {
@Autowired
private TikaContentDetector tikaContentDetector;
@Test
void detectByFileName() {
var ctx = tikaContentDetector.detect(ContentDetectorContext.builder().fileName("test.png").build());
assertEquals("png", ctx.getFormat());
assertEquals(".png", ctx.getExtension());
assertEquals("image/png", ctx.getMimeType());
ctx = tikaContentDetector.detect(ContentDetectorContext.builder().fileName("test.jpg").build());
assertEquals("jpg", ctx.getFormat());
assertEquals(".jpg", ctx.getExtension());
assertEquals("image/jpeg", ctx.getMimeType());
}
@Test
void detectByInputStream() {
var ctx = tikaContentDetector.detect(
ContentDetectorContext.builder().inputStream(TikaContentDetectorTest.class.getClassLoader().getResourceAsStream("test.png"))
.inputStreamEnabled(true).build());
assertEquals("png", ctx.getFormat());
assertEquals(".png", ctx.getExtension());
assertEquals("image/png", ctx.getMimeType());
write(ctx); // make sure we can still consume the input stream
ctx = tikaContentDetector.detect(
ContentDetectorContext.builder().inputStream(TikaContentDetectorTest.class.getClassLoader().getResourceAsStream("test.jpg"))
.inputStreamEnabled(true).build());
assertEquals("jpg", ctx.getFormat());
assertEquals(".jpg", ctx.getExtension());
assertEquals("image/jpeg", ctx.getMimeType());
write(ctx);
}
@Test
void reuseStream() throws IOException {
var ctx = tikaContentDetector.detect(
ContentDetectorContext.builder().inputStream(TikaContentDetectorTest.class.getClassLoader().getResourceAsStream("test.png"))
.inputStreamEnabled(true).build());
// we can run the detection again with the same stream
ctx = tikaContentDetector
.detect(ContentDetectorContext.builder().inputStream(ctx.getInputStream()).inputStreamEnabled(true).build());
assertEquals("image/png", ctx.getMimeType());
IOUtils.copy(ctx.getInputStream(), new FileOutputStream("build/test.png"));
try (var expectedIs = TikaContentDetectorTest.class.getClassLoader().getResourceAsStream("test.png");
var actualIs = new FileInputStream("build/test.png")) {
requireNonNull(expectedIs);
var expectedImage = ImageIO.read(expectedIs);
var actualImage = ImageIO.read(actualIs);
var result = new ImageComparison(expectedImage, actualImage).setAllowingPercentOfDifferentPixels(0).compareImages();
log.info("Image diff percentage: {}", result.getDifferencePercent());
assertEquals(MATCH, result.getImageComparisonState(), "The images should be identical");
}
}
@Test
void illegalArguments() {
var exception = assertThrows(ContentDetectorException.class, () -> {
tikaContentDetector.detect(ContentDetectorContext.builder()
.inputStream(TikaContentDetectorTest.class.getClassLoader().getResourceAsStream("test.png")).build());
});
assertNotNull(exception);
}
private void write(ContentDetectorContext ctx) {
try (var is = ctx.getInputStream()) {
IOUtils.copy(is, new FileOutputStream("build/detector" + ctx.getExtension()));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
@@ -0,0 +1,56 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.infrastructure.contentstore.policy;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.fineract.infrastructure.TestConfiguration;
import org.apache.fineract.infrastructure.contentstore.exception.ContentPolicyException;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ContextConfiguration;
@Slf4j
@SpringBootTest
@ContextConfiguration(classes = TestConfiguration.class)
class MimeContentPolicyTest {
@Autowired
private MimeContentPolicy mimeContentPolicy;
@Test
void mimeTypeMismatch() {
var path = "tmp/test-gif.png";
var mime = "image/png";
var ctx = ContentPolicyContext.builder().path(path).mimeType(mime)
.inputStream(MimeContentPolicyTest.class.getClassLoader().getResourceAsStream("test-gif.png")).build();
var exception = assertThrows(ContentPolicyException.class, () -> {
mimeContentPolicy.check(ctx);
});
assertThat(exception).isNotNull();
log.info("Error message: {}", exception.getMessage());
}
}
@@ -0,0 +1,63 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.infrastructure.contentstore.policy;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
import java.util.List;
import lombok.extern.slf4j.Slf4j;
import org.apache.fineract.infrastructure.TestConfiguration;
import org.apache.fineract.infrastructure.contentstore.exception.ContentPolicyException;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ContextConfiguration;
@Slf4j
@SpringBootTest
@ContextConfiguration(classes = TestConfiguration.class)
class TraversalContentPolicyTest {
@Autowired
private TraversalContentPolicy traversalContentPolicy;
@Test
void pathTraversal() {
var paths = List.of("/tmp/../17/michael.vorburger-crepes.jpg", "../17/michael.vorburger-crepes.jpg",
"/tmp/..//17//michael.vorburger-crepes.jpg", "/tmp/..//17/michael.vorburger-crepes.jpg",
"..//17/michael.vorburger-crepes.jpg", "../../../../../../../../../../tmp/michael.vorburger-crepes.jpg",
"/tmp/../../../../../../../../../../tmp/image-text-wrong-content.jsp",
"../../../../../../../../../../tmp/image-text-wrong-content.jsp", "/test/../tmp/image-text-wrong-content.jsp");
paths.forEach(path -> {
log.info("Checking path: {}", path);
var exception = assertThrows(ContentPolicyException.class, () -> {
var ctx = ContentPolicyContext.builder().path(path).mimeType("image/jpeg").build();
traversalContentPolicy.check(ctx);
});
assertThat(exception).isNotNull();
assertThat(exception.getMessage()).startsWith("Trying to overwrite a sibling file:");
});
}
}
@@ -0,0 +1,170 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.infrastructure.contentstore.processor;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.apache.fineract.infrastructure.contentstore.processor.DataUrlDecoderContentProcessor.DATA_URL_DECODE_RESULT_CONTENT_TYPE;
import static org.apache.fineract.infrastructure.contentstore.processor.DataUrlEncoderContentProcessor.DATA_URL_ENCODE_PARAM_CONTENT_TYPE;
import static org.apache.fineract.infrastructure.contentstore.processor.DataUrlEncoderContentProcessor.DATA_URL_ENCODE_PARAM_ENCODING;
import static org.apache.fineract.infrastructure.contentstore.processor.ImageResizeContentProcessor.IMAGE_RESIZE_PARAM_FORMAT;
import static org.apache.fineract.infrastructure.contentstore.processor.ImageResizeContentProcessor.IMAGE_RESIZE_PARAM_MAX_HEIGHT;
import static org.apache.fineract.infrastructure.contentstore.processor.ImageResizeContentProcessor.IMAGE_RESIZE_PARAM_MAX_WIDTH;
import static org.apache.fineract.infrastructure.contentstore.processor.SizeContentProcessor.SIZE_RESULT_VALUE;
import java.io.ByteArrayInputStream;
import java.io.FileOutputStream;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.fineract.infrastructure.TestConfiguration;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ContextConfiguration;
@Slf4j
@SpringBootTest
@ContextConfiguration(classes = TestConfiguration.class)
class ContentProcessorTest {
@Autowired
private Base64EncoderContentProcessor base64EncoderContentProcessor;
@Autowired
private Base64DecoderContentProcessor base64DecoderContentProcessor;
@Autowired
private DataUrlEncoderContentProcessor dataUrlEncoderContentProcessor;
@Autowired
private DataUrlDecoderContentProcessor dataUrlDecoderContentProcessor;
@Autowired
private ImageResizeContentProcessor imageResizeContentProcessor;
@Autowired
private SizeContentProcessor sizeContentProcessor;
static final byte[] DATA_BASE64 = """
iVBORw0KGgoAAAANSUhEUgAAANwAAADcCAYAAAAbWs+BAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJ
bWFnZVJlYWR5ccllPAAAAodJREFUeNrs3NFtg0AQRVGPRRNWyoCeUhM9LWWkjUw6iIQyCRvmnAKQ
F3S1/nqRmQ/gbzy9AhAcCA4QHAgOEBwIDgQHCA4EBwgOBAeCAwQHggMEB4IDBAeCg/tbvAJuJaJ2
pCcz3HDgLyUgOBAcCA4QHAgOEBwIDhAcCA4EBwgOBAcIDgQHggMEB4IDTmm3aRKxlW5erOva6v2N
sUft96jdIMndDQcIDgQHggMEB4IDBAeCA8EBggPBAYIDwQGCA8GB4ADBgeAAwcHFpt806bZBMvvv
27b32g2SzOgUnBsOBAeCAwQHggMEB4IDwQGCA8EBggPBgeAAwYHgAMGB4ADBgeCggcjM2gcWb5BU
m30zpNt5j+Mofd4Y+9QbKW44EBwIDhAcCA4QHAgOBAcIDgQHCA4EB4IDBAeCAwQHggMEB4KDBpZu
B67e0Oi2GdJtE8YNB4IDBAeCA8EBggPBAYIDwQGCA8GB4ADBgeAAwYHgQHCA4EBwwGmRmbUPjLfa
Bz5erT6IzZCfGWMPNxwgOBAcCA4QHAgOEBwIDgQHCA4EBwgOBAeC8wpAcCA4QHAgOEBwcKl/sGlS
7eWr31jmsGkCCA4EB4IDBAeCAwQHggPBAYIDwQGCA8EBggPBgeAAwYHgAMHBtco3Tcp/4PQbKdV6
ba7MvkHihgPBAYIDwYHgAMGB4ADBgeAAwYHgQHCA4EBwgOBAcCA4QHAgOOC06TdNyg8cz+IDd9sg
+QjZuOFAcIDgQHAgOEBwIDhAcCA4EBwgOBAcIDgQHCA4EBwIDhAcCA74xtLtwJmfNjlww4HgAMGB
4ADBgeBAcIDgQHCA4EBwgOBAcCA4QHAgOEBwIDgQHPB7vgQYAPVcRHV5+lfgAAAAAElFTkSuQmCC""".getBytes(UTF_8);
private static final byte[] DATA_URL = """
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAANwAAADcCAYAAAAbWs+BAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJ
bWFnZVJlYWR5ccllPAAAAodJREFUeNrs3NFtg0AQRVGPRRNWyoCeUhM9LWWkjUw6iIQyCRvmnAKQ
F3S1/nqRmQ/gbzy9AhAcCA4QHAgOEBwIDgQHCA4EBwgOBAeCAwQHggMEB4IDBAeCg/tbvAJuJaJ2
pCcz3HDgLyUgOBAcCA4QHAgOEBwIDhAcCA4EBwgOBAcIDgQHggMEB4IDTmm3aRKxlW5erOva6v2N
sUft96jdIMndDQcIDgQHggMEB4IDBAeCA8EBggPBAYIDwQGCA8GB4ADBgeAAwcHFpt806bZBMvvv
27b32g2SzOgUnBsOBAeCAwQHggMEB4IDwQGCA8EBggPBgeAAwYHgAMGB4ADBgeCggcjM2gcWb5BU
m30zpNt5j+Mofd4Y+9QbKW44EBwIDhAcCA4QHAgOBAcIDgQHCA4EB4IDBAeCAwQHggMEB4KDBpZu
B67e0Oi2GdJtE8YNB4IDBAeCA8EBggPBAYIDwQGCA8GB4ADBgeAAwYHgQHCA4EBwwGmRmbUPjLfa
Bz5erT6IzZCfGWMPNxwgOBAcCA4QHAgOEBwIDgQHCA4EBwgOBAeC8wpAcCA4QHAgOEBwcKl/sGlS
7eWr31jmsGkCCA4EB4IDBAeCAwQHggPBAYIDwQGCA8EBggPBgeAAwYHgAMHBtco3Tcp/4PQbKdV6
ba7MvkHihgPBAYIDwYHgAMGB4ADBgeAAwYHgQHCA4EBwgOBAcCA4QHAgOOC06TdNyg8cz+IDd9sg
+QjZuOFAcIDgQHAgOEBwIDhAcCA4EBwgOBAcIDgQHCA4EBwIDhAcCA74xtLtwJmfNjlww4HgAMGB
4ADBgeBAcIDgQHCA4EBwgOBAcCA4QHAgOEBwIDgQHPB7vgQYAPVcRHV5+lfgAAAAAElFTkSuQmCC""".getBytes(UTF_8);
@Test
void process() {
final var ctx = sizeContentProcessor.then(base64DecoderContentProcessor).process(new ByteArrayInputStream(DATA_BASE64));
write(ctx, "process.png");
String type = ctx.getResult(DATA_URL_DECODE_RESULT_CONTENT_TYPE);
Long size = ctx.getResult(SIZE_RESULT_VALUE);
log.info("Result: {} of size {}", type, size);
}
@Test
void dataUrlDecode() {
final var ctx = dataUrlDecoderContentProcessor.then(base64DecoderContentProcessor).then(imageResizeContentProcessor)
.then(sizeContentProcessor).process(new ContentProcessorContext(new ByteArrayInputStream(DATA_URL),
Map.of(IMAGE_RESIZE_PARAM_MAX_WIDTH, 110, IMAGE_RESIZE_PARAM_MAX_HEIGHT, 110, IMAGE_RESIZE_PARAM_FORMAT, "png")));
write(ctx, "data-url-decode.png");
String type = ctx.getResult(DATA_URL_DECODE_RESULT_CONTENT_TYPE);
Long size = ctx.getResult(SIZE_RESULT_VALUE);
log.info("Result: {} of size {}", type, size);
}
@Test
void dataUrlEncodePng() {
final var ctx = imageResizeContentProcessor.then(base64EncoderContentProcessor).then(dataUrlEncoderContentProcessor)
.process(new ContentProcessorContext(ContentProcessorTest.class.getClassLoader().getResourceAsStream("test.png"),
Map.of(IMAGE_RESIZE_PARAM_MAX_WIDTH, 110, IMAGE_RESIZE_PARAM_MAX_HEIGHT, 110, IMAGE_RESIZE_PARAM_FORMAT, "png",
DATA_URL_ENCODE_PARAM_CONTENT_TYPE, "image/png", DATA_URL_ENCODE_PARAM_ENCODING, "base64")));
write(ctx, "data-url-encode-png.txt");
String type = ctx.getResult(DATA_URL_DECODE_RESULT_CONTENT_TYPE);
Long size = ctx.getResult(SIZE_RESULT_VALUE);
log.info("Result: {} of size {}", type, size);
}
@Test
void dataUrlEncodeJpeg() {
final var ctx = imageResizeContentProcessor.then(base64EncoderContentProcessor).then(dataUrlEncoderContentProcessor)
.process(new ContentProcessorContext(ContentProcessorTest.class.getClassLoader().getResourceAsStream("test-large.jpg"),
Map.of(IMAGE_RESIZE_PARAM_MAX_WIDTH, 300, IMAGE_RESIZE_PARAM_MAX_HEIGHT, 300, IMAGE_RESIZE_PARAM_FORMAT, "jpg",
DATA_URL_ENCODE_PARAM_CONTENT_TYPE, "image/png", DATA_URL_ENCODE_PARAM_ENCODING, "base64")));
write(ctx, "data-url-encode-jpg.txt");
String type = ctx.getResult(DATA_URL_DECODE_RESULT_CONTENT_TYPE);
Long size = ctx.getResult(SIZE_RESULT_VALUE);
log.info("Result: {} of size {}", type, size);
}
@Test
void base64() {
final var ctx = base64DecoderContentProcessor.then(sizeContentProcessor).process(new ByteArrayInputStream(DATA_BASE64));
write(ctx, "base64.png");
String type = ctx.getResult(DATA_URL_DECODE_RESULT_CONTENT_TYPE);
Long size = ctx.getResult(SIZE_RESULT_VALUE);
log.info("Result: {} of size {}", type, size);
}
private void write(ContentProcessorContext ctx, String fileName) {
try (var is = ctx.getInputStream()) {
IOUtils.copy(is, new FileOutputStream("build/" + fileName));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
@@ -0,0 +1,85 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.infrastructure.contentstore.service;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.nio.file.Files;
import java.nio.file.Path;
import lombok.extern.slf4j.Slf4j;
import org.apache.fineract.infrastructure.TestConfiguration;
import org.apache.fineract.infrastructure.core.config.FineractProperties;
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ContextConfiguration;
@Slf4j
@SpringBootTest
@ContextConfiguration(classes = TestConfiguration.class)
class FileContentStoreServiceTest {
@Autowired
private FileContentStoreService fileContentStoreService;
@Autowired
private FineractProperties properties;
@Test
void upload() {
setTenant();
var path = fileContentStoreService.upload("some/path/test.jpg",
FileContentStoreServiceTest.class.getClassLoader().getResourceAsStream("test.jpg"), "image/jpeg");
var rootFolder = getRootFolder();
log.info("Path: {} ({})", path, rootFolder);
var p = rootFolder.resolve(path);
log.info("Complete path: {}", p);
assertTrue(Files.exists(p));
}
@Test
void relativePath() {
var rootPath = Path.of("/tmp/fineract/DefaultDemoTenant");
var fullPath = Path.of("/tmp/fineract/DefaultDemoTenant/images/staff/1/PwVhJDLHyxUppiby/michael.vorburger-crepes.jpg");
var relativePath = rootPath.relativize(fullPath);
assertEquals(Path.of("images/staff/1/PwVhJDLHyxUppiby/michael.vorburger-crepes.jpg"), relativePath);
log.info("Relative path: {}", relativePath);
}
private Path getRootFolder() {
return Path.of(properties.getContent().getFilesystem().getRootFolder(),
ThreadLocalContextUtil.getTenant().getName().replaceAll(" ", "").trim());
}
private void setTenant() {
ThreadLocalContextUtil
.setTenant(FineractPlatformTenant.builder().id(1L).name("Test Tenant").tenantIdentifier("test-tenant").build());
}
}
@@ -0,0 +1,36 @@
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
debug=false
fineract.content.regex-whitelist-enabled=true
fineract.content.regex-whitelist=.*\\.pdf$,.*\\.doc,.*\\.docx,.*\\.xls,.*\\.xlsx,.*\\.jpg,.*\\.jpeg,.*\\.png
fineract.content.mime-whitelist-enabled=true
fineract.content.mime-whitelist=application/pdf,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document,application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,image/jpeg,image/png
fineract.content.filesystem.enabled=true
fineract.content.filesystem.rootFolder=build/.fineract
fineract.content.s3.enabled=false
fineract.content.s3.bucketName=
fineract.content.s3.accessKey=
fineract.content.s3.secretKey=
fineract.content.s3.region=
fineract.content.s3.endpoint=
fineract.content.s3.path-style-addressing-enabled=false
Binary file not shown.

After

Width:  |  Height:  |  Size: 995 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 741 B