Skip to content

Commit a2b2b28

Browse files
committed
FINERACT-1878: Separate profile image paths for staff and clients
1 parent 92f8b3d commit a2b2b28

File tree

2 files changed

+129
-4
lines changed

2 files changed

+129
-4
lines changed

fineract-document/src/main/java/org/apache/fineract/infrastructure/documentmanagement/service/ImageWritePlatformServiceImpl.java

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ public ImageCreateResponse createImage(final ImageCreateRequest request) {
6565
// TODO: keeping the path segment always "clients" not consistent how this works with documents
6666
request.setEntityType(DEFAULT_ENTITY_TYPE);
6767
}
68+
final var imageEntityType = normalizeImageEntityType(request.getEntityType());
6869

6970
if (StringUtils.isEmpty(request.getFileName())) {
7071
// NOTE: defacto limiting the uploads to JPEG files, same behavior as before
@@ -83,12 +84,11 @@ public ImageCreateResponse createImage(final ImageCreateRequest request) {
8384
}
8485

8586
// TODO: make "prefix" configurable?
86-
var path = getPath(STORE_PREFIX, request.getEntityType(), request.getEntityId(), request.getFileName(),
87-
storeService.getDelimiter());
87+
var path = getPath(STORE_PREFIX, imageEntityType, request.getEntityId(), request.getFileName(), storeService.getDelimiter());
8888

8989
final var imagePath = storeService.upload(path, request.getStream(), request.getType());
9090

91-
final var result = imageIdAdapters.stream().filter(imageIdAdapter -> imageIdAdapter.accept(request.getEntityType())).findFirst()
91+
final var result = imageIdAdapters.stream().filter(imageIdAdapter -> imageIdAdapter.accept(imageEntityType)).findFirst()
9292
.flatMap(imageIdAdapter -> imageIdAdapter.get(request.getEntityId()))
9393
.flatMap(imageIdResult -> imageRepository.findById(imageIdResult.getId())).map(image -> {
9494
// delete old image
@@ -99,7 +99,7 @@ public ImageCreateResponse createImage(final ImageCreateRequest request) {
9999
.map(image -> image.setLocation(imagePath).setStorageType(storeService.getType().getValue())).map(imageRepository::save)
100100
.map(image -> ImageCreateResponse.builder().resourceId(image.getId()).build());
101101

102-
imageIdAdapters.stream().filter(imageIdAdapter -> imageIdAdapter.accept(request.getEntityType())).findFirst()
102+
imageIdAdapters.stream().filter(imageIdAdapter -> imageIdAdapter.accept(imageEntityType)).findFirst()
103103
.ifPresent(imageIdAdapter -> result.ifPresent(
104104
imageCreateResponse -> imageIdAdapter.set(request.getEntityId(), imageCreateResponse.getResourceId())));
105105

@@ -135,6 +135,16 @@ private Optional<ImageDeleteResponse> delete(final String entityType, final Long
135135
});
136136
}
137137

138+
private String normalizeImageEntityType(final String entityType) {
139+
if ("staff".equalsIgnoreCase(entityType)) {
140+
return "staff";
141+
}
142+
if ("clients".equalsIgnoreCase(entityType)) {
143+
return DEFAULT_ENTITY_TYPE;
144+
}
145+
return entityType;
146+
}
147+
138148
private String getPath(final String prefix, final String entityType, final Long entityId, final String fileName, String delimiter) {
139149
requireNonNull(prefix);
140150
requireNonNull(entityType);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
/**
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.apache.fineract.infrastructure.documentmanagement.service;
20+
21+
import static org.junit.jupiter.api.Assertions.assertEquals;
22+
import static org.mockito.ArgumentMatchers.any;
23+
import static org.mockito.ArgumentMatchers.anyLong;
24+
import static org.mockito.ArgumentMatchers.anyString;
25+
import static org.mockito.ArgumentMatchers.eq;
26+
import static org.mockito.Mockito.verify;
27+
import static org.mockito.Mockito.when;
28+
29+
import java.io.ByteArrayInputStream;
30+
import java.io.InputStream;
31+
import java.util.List;
32+
import java.util.Optional;
33+
import org.apache.fineract.infrastructure.contentstore.data.ContentStoreType;
34+
import org.apache.fineract.infrastructure.contentstore.detector.ContentDetectorManager;
35+
import org.apache.fineract.infrastructure.contentstore.service.ContentStoreService;
36+
import org.apache.fineract.infrastructure.documentmanagement.adapter.EntityImageIdAdapter;
37+
import org.apache.fineract.infrastructure.documentmanagement.data.ImageCreateRequest;
38+
import org.apache.fineract.infrastructure.documentmanagement.domain.Image;
39+
import org.apache.fineract.infrastructure.documentmanagement.domain.ImageRepository;
40+
import org.junit.jupiter.api.BeforeEach;
41+
import org.junit.jupiter.api.Test;
42+
import org.junit.jupiter.api.extension.ExtendWith;
43+
import org.mockito.ArgumentCaptor;
44+
import org.mockito.Mock;
45+
import org.mockito.junit.jupiter.MockitoExtension;
46+
47+
@ExtendWith(MockitoExtension.class)
48+
class ImageWritePlatformServiceImplTest {
49+
50+
@Mock
51+
private EntityImageIdAdapter clientImageIdAdapter;
52+
@Mock
53+
private EntityImageIdAdapter staffImageIdAdapter;
54+
@Mock
55+
private ContentStoreService contentStoreService;
56+
@Mock
57+
private ImageRepository imageRepository;
58+
@Mock
59+
private ContentDetectorManager contentDetectorManager;
60+
61+
private ImageWritePlatformServiceImpl underTest;
62+
63+
@BeforeEach
64+
void setUp() {
65+
underTest = new ImageWritePlatformServiceImpl(List.of(clientImageIdAdapter, staffImageIdAdapter), contentStoreService,
66+
imageRepository, contentDetectorManager);
67+
68+
when(contentStoreService.getDelimiter()).thenReturn("/");
69+
when(contentStoreService.getType()).thenReturn(ContentStoreType.FILE_SYSTEM);
70+
when(contentStoreService.upload(anyString(), any(InputStream.class), anyString()))
71+
.thenAnswer(invocation -> invocation.getArgument(0));
72+
when(imageRepository.save(any(Image.class))).thenAnswer(invocation -> {
73+
Image image = invocation.getArgument(0);
74+
image.setId(99L);
75+
return image;
76+
});
77+
}
78+
79+
@Test
80+
void createImageShouldStoreStaffImageUnderStaffDirectory() {
81+
Long entityId = 7L;
82+
when(staffImageIdAdapter.accept("staff")).thenReturn(true);
83+
when(staffImageIdAdapter.get(entityId)).thenReturn(Optional.empty());
84+
when(staffImageIdAdapter.set(eq(entityId), anyLong())).thenReturn(Optional.empty());
85+
when(clientImageIdAdapter.accept(anyString())).thenReturn(false);
86+
87+
ImageCreateRequest request = ImageCreateRequest.builder().entityType("STAFF").entityId(entityId).fileName("profile.png")
88+
.type("image/png").stream(new ByteArrayInputStream(new byte[] { 1, 2, 3 })).build();
89+
90+
var response = underTest.createImage(request);
91+
92+
ArgumentCaptor<String> pathCaptor = ArgumentCaptor.forClass(String.class);
93+
verify(contentStoreService).upload(pathCaptor.capture(), any(InputStream.class), eq("image/png"));
94+
assertEquals("images/staff/7/profile.png", pathCaptor.getValue());
95+
assertEquals(99L, response.getResourceId());
96+
}
97+
98+
@Test
99+
void createImageShouldStoreClientImageUnderClientsDirectory() {
100+
Long entityId = 7L;
101+
when(clientImageIdAdapter.accept("clients")).thenReturn(true);
102+
when(clientImageIdAdapter.get(entityId)).thenReturn(Optional.empty());
103+
when(clientImageIdAdapter.set(eq(entityId), anyLong())).thenReturn(Optional.empty());
104+
105+
ImageCreateRequest request = ImageCreateRequest.builder().entityType("CLIENTS").entityId(entityId).fileName("profile.png")
106+
.type("image/png").stream(new ByteArrayInputStream(new byte[] { 1, 2, 3 })).build();
107+
108+
var response = underTest.createImage(request);
109+
110+
ArgumentCaptor<String> pathCaptor = ArgumentCaptor.forClass(String.class);
111+
verify(contentStoreService).upload(pathCaptor.capture(), any(InputStream.class), eq("image/png"));
112+
assertEquals("images/clients/7/profile.png", pathCaptor.getValue());
113+
assertEquals(99L, response.getResourceId());
114+
}
115+
}

0 commit comments

Comments
 (0)