diff --git a/support-portal-backend/src/main/java/net/shyshkin/study/fullstack/supportportal/backend/config/LocalStackAmazonConfig.java b/support-portal-backend/src/main/java/net/shyshkin/study/fullstack/supportportal/backend/config/LocalStackAmazonConfig.java new file mode 100644 index 0000000..a042234 --- /dev/null +++ b/support-portal-backend/src/main/java/net/shyshkin/study/fullstack/supportportal/backend/config/LocalStackAmazonConfig.java @@ -0,0 +1,44 @@ +package net.shyshkin.study.fullstack.supportportal.backend.config; + +import com.amazonaws.auth.AWSStaticCredentialsProvider; +import com.amazonaws.auth.BasicAWSCredentials; +import com.amazonaws.client.builder.AwsClientBuilder; +import com.amazonaws.services.s3.AmazonS3; +import com.amazonaws.services.s3.AmazonS3ClientBuilder; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; + +@Configuration +@Profile("image-s3-localstack") +public class LocalStackAmazonConfig { + + @Value("${config.aws.region}") private String region; + @Value("${config.aws.s3.url}") private String s3EndpointUrl; + @Value("${config.aws.s3.bucket-name}") private String bucketName; + @Value("${config.aws.s3.access-key}") private String accessKey; + @Value("${config.aws.s3.secret-key}") private String secretKey; + + @Bean + public AmazonS3 s3() { + + return AmazonS3ClientBuilder + .standard() + .withCredentials(getCredentialsProvider()) + .withEndpointConfiguration(getEndpointConfiguration(s3EndpointUrl)) + .build(); + } + + private AwsClientBuilder.EndpointConfiguration getEndpointConfiguration(String url) { + return new AwsClientBuilder.EndpointConfiguration(url, region); + } + + private AWSStaticCredentialsProvider getCredentialsProvider() { + return new AWSStaticCredentialsProvider(getBasicAWSCredentials()); + } + + private BasicAWSCredentials getBasicAWSCredentials() { + return new BasicAWSCredentials(accessKey, secretKey); + } +} \ No newline at end of file diff --git a/support-portal-backend/src/main/java/net/shyshkin/study/fullstack/supportportal/backend/service/FileSystemProfileImageService.java b/support-portal-backend/src/main/java/net/shyshkin/study/fullstack/supportportal/backend/service/FileSystemProfileImageService.java index b077dc1..34f79a8 100644 --- a/support-portal-backend/src/main/java/net/shyshkin/study/fullstack/supportportal/backend/service/FileSystemProfileImageService.java +++ b/support-portal-backend/src/main/java/net/shyshkin/study/fullstack/supportportal/backend/service/FileSystemProfileImageService.java @@ -17,7 +17,7 @@ import static net.shyshkin.study.fullstack.supportportal.backend.constant.FileCo @Slf4j @Service -@Profile("!image-s3") +@Profile("!image-s3 && !image-s3-localstack") public class FileSystemProfileImageService implements ProfileImageService { @Override diff --git a/support-portal-backend/src/main/java/net/shyshkin/study/fullstack/supportportal/backend/service/S3ProfileImageService.java b/support-portal-backend/src/main/java/net/shyshkin/study/fullstack/supportportal/backend/service/S3ProfileImageService.java index b277db4..1f1664f 100644 --- a/support-portal-backend/src/main/java/net/shyshkin/study/fullstack/supportportal/backend/service/S3ProfileImageService.java +++ b/support-portal-backend/src/main/java/net/shyshkin/study/fullstack/supportportal/backend/service/S3ProfileImageService.java @@ -21,7 +21,7 @@ import java.util.UUID; @Slf4j @Service -@Profile("image-s3") +@Profile({"image-s3", "image-s3-localstack"}) @RequiredArgsConstructor public class S3ProfileImageService implements ProfileImageService { diff --git a/support-portal-backend/src/main/resources/application.yml b/support-portal-backend/src/main/resources/application.yml index 6362d81..5e5ec2c 100644 --- a/support-portal-backend/src/main/resources/application.yml +++ b/support-portal-backend/src/main/resources/application.yml @@ -143,5 +143,21 @@ app: amazon-s3: bucket-name: portal-user-profile-images +--- +spring: + config: + activate: + on-profile: image-s3-localstack +app: + amazon-s3: + bucket-name: portal-user-profile-images +config: + aws: + region: eu-north-1 + s3: + url: http://127.0.0.1:4566 + bucket-name: portal-user-profile-images + access-key: localstack + secret-key: localstack diff --git a/support-portal-backend/src/test/java/net/shyshkin/study/fullstack/supportportal/backend/service/UserServiceLocalStackManualTest.java b/support-portal-backend/src/test/java/net/shyshkin/study/fullstack/supportportal/backend/service/UserServiceLocalStackManualTest.java new file mode 100644 index 0000000..8ff3149 --- /dev/null +++ b/support-portal-backend/src/test/java/net/shyshkin/study/fullstack/supportportal/backend/service/UserServiceLocalStackManualTest.java @@ -0,0 +1,63 @@ +package net.shyshkin.study.fullstack.supportportal.backend.service; + +import lombok.extern.slf4j.Slf4j; +import net.shyshkin.study.fullstack.supportportal.backend.common.BaseUserTest; +import net.shyshkin.study.fullstack.supportportal.backend.domain.User; +import org.junit.jupiter.api.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.mock.web.MockMultipartFile; +import org.springframework.test.context.ActiveProfiles; + +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; + +@Slf4j +@ActiveProfiles({"local", "image-s3-localstack"}) +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +@Disabled("Only for manual testing. First start docker-compose") +class UserServiceLocalStackManualTest extends BaseUserTest { + + @Autowired + UserService userService; + + @Test + @Order(10) + void updateProfileImage() { + //given + User fakeUser = createRandomUser(); + user = userRepository.save(fakeUser); + UUID userId = user.getUserId(); + String filename = "avatar.jpg"; + + //when + MockMultipartFile multipartFile = new MockMultipartFile("file", "test.jpg", + "image/jpeg", ("Spring Framework" + UUID.randomUUID()).getBytes()); + userService.updateProfileImage(userId, multipartFile); + + //then + + assertThat(user.getProfileImageUrl()).contains(userId + "/profile-image"); + } + + @Test + @Order(20) + void getImageByUserId() { + //given + UUID userId = user.getUserId(); + String filename = "avatar.jpg"; + + //when + byte[] imageByUserId = userService.getImageByUserId(userId, filename); + + //then + assertAll( + () -> assertThat(imageByUserId).isNotNull(), + () -> { + String imageContent = new String(imageByUserId); + assertThat(imageContent).contains("Spring Framework"); + } + ); + } +} \ No newline at end of file