diff --git a/support-portal-backend/src/main/java/net/shyshkin/study/fullstack/supportportal/backend/SupportPortalBackendApplication.java b/support-portal-backend/src/main/java/net/shyshkin/study/fullstack/supportportal/backend/SupportPortalBackendApplication.java index 692f235..375d9fb 100644 --- a/support-portal-backend/src/main/java/net/shyshkin/study/fullstack/supportportal/backend/SupportPortalBackendApplication.java +++ b/support-portal-backend/src/main/java/net/shyshkin/study/fullstack/supportportal/backend/SupportPortalBackendApplication.java @@ -1,17 +1,13 @@ package net.shyshkin.study.fullstack.supportportal.backend; -import net.shyshkin.study.fullstack.supportportal.backend.constant.FileConstant; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import java.io.File; - @SpringBootApplication public class SupportPortalBackendApplication { public static void main(String[] args) { SpringApplication.run(SupportPortalBackendApplication.class, args); - new File(FileConstant.USER_FOLDER).mkdirs(); } } diff --git a/support-portal-backend/src/main/java/net/shyshkin/study/fullstack/supportportal/backend/constant/FileConstant.java b/support-portal-backend/src/main/java/net/shyshkin/study/fullstack/supportportal/backend/constant/FileConstant.java index 6af76c9..c414a12 100644 --- a/support-portal-backend/src/main/java/net/shyshkin/study/fullstack/supportportal/backend/constant/FileConstant.java +++ b/support-portal-backend/src/main/java/net/shyshkin/study/fullstack/supportportal/backend/constant/FileConstant.java @@ -7,6 +7,7 @@ public class FileConstant { public static final String USER_FOLDER = System.getProperty("user.home") + "/supportportal/user/"; public static final String DIRECTORY_CREATED = "Created directory for: "; public static final String DEFAULT_USER_IMAGE_PATH = "/user/image/profile/"; + public static final String USER_IMAGE_FILENAME = "avatar.jpg"; public static final String FILE_SAVED_IN_FILE_SYSTEM = "Saved file in file system by name: "; public static final String DOT = "."; public static final String FORWARD_SLASH = "/"; diff --git a/support-portal-backend/src/main/java/net/shyshkin/study/fullstack/supportportal/backend/service/UserServiceImpl.java b/support-portal-backend/src/main/java/net/shyshkin/study/fullstack/supportportal/backend/service/UserServiceImpl.java index 58cfb34..a8eb526 100644 --- a/support-portal-backend/src/main/java/net/shyshkin/study/fullstack/supportportal/backend/service/UserServiceImpl.java +++ b/support-portal-backend/src/main/java/net/shyshkin/study/fullstack/supportportal/backend/service/UserServiceImpl.java @@ -2,7 +2,6 @@ package net.shyshkin.study.fullstack.supportportal.backend.service; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import net.shyshkin.study.fullstack.supportportal.backend.constant.FileConstant; import net.shyshkin.study.fullstack.supportportal.backend.domain.Role; import net.shyshkin.study.fullstack.supportportal.backend.domain.User; import net.shyshkin.study.fullstack.supportportal.backend.domain.UserPrincipal; @@ -22,11 +21,17 @@ import org.springframework.web.multipart.MultipartFile; import org.springframework.web.servlet.support.ServletUriComponentsBuilder; import javax.transaction.Transactional; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.time.LocalDateTime; import java.util.List; import java.util.Objects; import java.util.UUID; +import static net.shyshkin.study.fullstack.supportportal.backend.constant.FileConstant.*; + @Slf4j @Service @RequiredArgsConstructor @@ -81,10 +86,11 @@ public class UserServiceImpl implements UserService { return addNewUser(newUserDto); } - private String getTemporaryProfileImageUrl(String username) { + private String generateProfileImageUrl(String userId) { return ServletUriComponentsBuilder.fromCurrentContextPath() - .path(FileConstant.DEFAULT_USER_IMAGE_PATH) - .pathSegment(username) + .path(DEFAULT_USER_IMAGE_PATH) + .pathSegment(userId) + .pathSegment(USER_IMAGE_FILENAME) .toUriString(); } @@ -130,7 +136,7 @@ public class UserServiceImpl implements UserService { newUser.setPassword(encodedPassword); newUser.setUserId(generateUserId()); - newUser.setProfileImageUrl(getTemporaryProfileImageUrl(username)); + newUser.setProfileImageUrl(generateProfileImageUrl(newUser.getUserId())); userRepository.save(newUser); saveProfileImage(newUser, userDto.getProfileImage()); @@ -147,6 +153,18 @@ public class UserServiceImpl implements UserService { private void saveProfileImage(User user, MultipartFile profileImage) { if (profileImage == null) return; + + Path userFolder = Paths.get(USER_FOLDER, user.getUserId()); + try { + if (Files.notExists(userFolder)) { + Files.createDirectories(userFolder); + log.debug(DIRECTORY_CREATED); + } + profileImage.transferTo(userFolder.resolve(USER_IMAGE_FILENAME)); + log.debug(FILE_SAVED_IN_FILE_SYSTEM + profileImage.getOriginalFilename()); + } catch (IOException exception) { + log.error("Can't save to file", exception); + } } @Override diff --git a/support-portal-backend/src/test/java/net/shyshkin/study/fullstack/supportportal/backend/common/BaseUserTest.java b/support-portal-backend/src/test/java/net/shyshkin/study/fullstack/supportportal/backend/common/BaseUserTest.java index 9b9d20a..1f84943 100644 --- a/support-portal-backend/src/test/java/net/shyshkin/study/fullstack/supportportal/backend/common/BaseUserTest.java +++ b/support-portal-backend/src/test/java/net/shyshkin/study/fullstack/supportportal/backend/common/BaseUserTest.java @@ -8,10 +8,14 @@ import net.shyshkin.study.fullstack.supportportal.backend.repository.UserReposit import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.ActiveProfiles; +import org.springframework.web.util.UriComponentsBuilder; import java.time.LocalDateTime; import java.util.UUID; +import static net.shyshkin.study.fullstack.supportportal.backend.constant.FileConstant.DEFAULT_USER_IMAGE_PATH; +import static net.shyshkin.study.fullstack.supportportal.backend.constant.FileConstant.USER_IMAGE_FILENAME; + @SpringBootTest @ActiveProfiles("local") public abstract class BaseUserTest { @@ -24,17 +28,18 @@ public abstract class BaseUserTest { protected static User user; protected User createRandomUser() { + String userId = UUID.randomUUID().toString(); return User.builder() .email(FAKER.bothify("????##@example.com")) .firstName(FAKER.name().firstName()) .lastName(FAKER.name().lastName()) .username(FAKER.name().username()) .password("{noop}bad_password") - .userId(UUID.randomUUID().toString()) + .userId(userId) .isActive(true) .isNotLocked(true) .joinDate(LocalDateTime.now()) - .profileImageUrl("http://url_to_profile_img") + .profileImageUrl(generateProfileImageUrl(userId)) .lastLoginDate(LocalDateTime.now()) .lastLoginDateDisplay(LocalDateTime.now()) .role("ROLE_ADMIN") @@ -54,4 +59,12 @@ public abstract class BaseUserTest { .build(); } + private String generateProfileImageUrl(String userId) { + return UriComponentsBuilder + .fromUriString("http://localhost:8080") + .path(DEFAULT_USER_IMAGE_PATH) + .pathSegment(userId) + .pathSegment(USER_IMAGE_FILENAME) + .toUriString(); + } } \ No newline at end of file diff --git a/support-portal-backend/src/test/java/net/shyshkin/study/fullstack/supportportal/backend/service/UserServiceTest.java b/support-portal-backend/src/test/java/net/shyshkin/study/fullstack/supportportal/backend/service/UserServiceTest.java index 3c3a9da..47372db 100644 --- a/support-portal-backend/src/test/java/net/shyshkin/study/fullstack/supportportal/backend/service/UserServiceTest.java +++ b/support-portal-backend/src/test/java/net/shyshkin/study/fullstack/supportportal/backend/service/UserServiceTest.java @@ -2,15 +2,21 @@ 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.constant.FileConstant; import net.shyshkin.study.fullstack.supportportal.backend.domain.Role; import net.shyshkin.study.fullstack.supportportal.backend.domain.User; import net.shyshkin.study.fullstack.supportportal.backend.domain.dto.UserDto; import org.assertj.core.api.ThrowableAssert; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.mock.web.MockMultipartFile; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UsernameNotFoundException; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.Optional; import java.util.UUID; @@ -105,4 +111,23 @@ class UserServiceTest extends BaseUserTest { .isInstanceOf(IllegalArgumentException.class) .hasMessage("No enum constant net.shyshkin.study.fullstack.supportportal.backend.domain.Role.FAKE_ROLE"); } + + @Test + void updateProfileImage() throws IOException { + //given + User fakeUser = createRandomUser(); + user = userRepository.save(fakeUser); + String username = user.getUsername(); + + //when + MockMultipartFile multipartFile = new MockMultipartFile("file", "test.txt", + "text/plain", ("Spring Framework" + UUID.randomUUID()).getBytes()); + userService.updateProfileImage(username, multipartFile); + + //then + Path path = Path.of(FileConstant.USER_FOLDER, user.getUserId(), FileConstant.USER_IMAGE_FILENAME); + log.debug("Path of created file: {}", path); + assertThat(Files.exists(path)).isTrue(); + assertThat(Files.getLastModifiedTime(path).toInstant()).isCloseTo(Instant.now(), within(100, ChronoUnit.MILLIS)); + } } \ No newline at end of file