From b5324f3337ea71f28301db497cec5da77e67511a Mon Sep 17 00:00:00 2001 From: ChernenkoVitaliy Date: Fri, 13 Dec 2024 17:24:35 +0200 Subject: [PATCH] Bugfix #7319 - Fixed incorrect saving for HabitTranslation for ua fields. (#7898) * Fixed functionality of saving HabitTranslation in saveHabitTranslationListsToHabitTranslationRepo method in HabitServiceImpl; Fixed necessary tests in HabitServiceImplTest; Added getHabitTranslationDtoEnAndUa method in ModelUtils; Added @NotBlank annotation in HabitTranslationDto for description, languageCode and name fields; Added @Valid annotation for validation HabitTranslationDto into CustomHabitDtoRequest; Added convertUa() and mapAllToList() methods into HabitTranslationMapper; Added necessary nests in HabitTranslationMapperTests; * Fixed sonar issues in HabitTranslationMapperTests; * Moved strings for language codes in AppConstant; Replced if/else to ObjectUtils.defaultNull; Added test for HabitTranslationMapperTests to improve coverage; * Formatted code in HabitTranslationMapperTests with formatter-maven-plagin; --- .../java/greencity/constant/AppConstant.java | 1 + .../dto/habit/CustomHabitDtoRequest.java | 3 + .../habittranslation/HabitTranslationDto.java | 4 ++ .../mapping/HabitTranslationMapper.java | 42 +++++++++++++ .../greencity/service/HabitServiceImpl.java | 15 +++-- .../src/test/java/greencity/ModelUtils.java | 15 +++++ .../mapping/HabitTranslationMapperTests.java | 62 ++++++++++++++++++- .../service/HabitServiceImplTest.java | 37 +++++++---- 8 files changed, 161 insertions(+), 18 deletions(-) diff --git a/service-api/src/main/java/greencity/constant/AppConstant.java b/service-api/src/main/java/greencity/constant/AppConstant.java index 9280d26f70..c4311afc76 100644 --- a/service-api/src/main/java/greencity/constant/AppConstant.java +++ b/service-api/src/main/java/greencity/constant/AppConstant.java @@ -14,6 +14,7 @@ public class AppConstant { public static final String AUTHORIZATION = "Authorization"; public static final String ROLE = "role"; public static final String DEFAULT_LANGUAGE_CODE = "en"; + public static final String LANGUAGE_CODE_UA = "ua"; public static final String DEFAULT_SOCIAL_NETWORK_IMAGE_HOST_PATH = "img/default_social_network_icon.png"; public static final Integer MAX_NUMBER_OF_HABIT_ASSIGNS_FOR_USER = 6; public static final int MIN_DAYS_DURATION = 7; diff --git a/service-api/src/main/java/greencity/dto/habit/CustomHabitDtoRequest.java b/service-api/src/main/java/greencity/dto/habit/CustomHabitDtoRequest.java index 957c3e62bc..318606d81e 100644 --- a/service-api/src/main/java/greencity/dto/habit/CustomHabitDtoRequest.java +++ b/service-api/src/main/java/greencity/dto/habit/CustomHabitDtoRequest.java @@ -14,9 +14,11 @@ import jakarta.validation.constraints.Min; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Size; +import org.springframework.validation.annotation.Validated; import java.util.List; import java.util.Set; +@Validated @NoArgsConstructor @AllArgsConstructor @Builder @@ -29,6 +31,7 @@ public class CustomHabitDtoRequest { @NotNull(message = ServiceValidationConstants.HABIT_COMPLEXITY) private Integer complexity; private Integer defaultDuration; + @Valid private List habitTranslations; private String image; private List customToDoListItemDto; diff --git a/service-api/src/main/java/greencity/dto/habittranslation/HabitTranslationDto.java b/service-api/src/main/java/greencity/dto/habittranslation/HabitTranslationDto.java index d5c7b10795..e606ae687b 100644 --- a/service-api/src/main/java/greencity/dto/habittranslation/HabitTranslationDto.java +++ b/service-api/src/main/java/greencity/dto/habittranslation/HabitTranslationDto.java @@ -1,6 +1,7 @@ package greencity.dto.habittranslation; import java.io.Serializable; +import jakarta.validation.constraints.NotBlank; import lombok.NoArgsConstructor; import lombok.AllArgsConstructor; import lombok.EqualsAndHashCode; @@ -15,9 +16,12 @@ @EqualsAndHashCode @Builder public class HabitTranslationDto implements Serializable { + @NotBlank private String description; private String habitItem; + @NotBlank private String languageCode; + @NotBlank private String name; private String descriptionUa; private String nameUa; diff --git a/service/src/main/java/greencity/mapping/HabitTranslationMapper.java b/service/src/main/java/greencity/mapping/HabitTranslationMapper.java index d92781fa8b..73e2a7d972 100644 --- a/service/src/main/java/greencity/mapping/HabitTranslationMapper.java +++ b/service/src/main/java/greencity/mapping/HabitTranslationMapper.java @@ -1,7 +1,9 @@ package greencity.mapping; +import greencity.constant.AppConstant; import greencity.dto.habittranslation.HabitTranslationDto; import greencity.entity.HabitTranslation; +import org.apache.commons.lang3.ObjectUtils; import org.modelmapper.AbstractConverter; import org.springframework.stereotype.Component; import java.util.List; @@ -18,6 +20,28 @@ protected HabitTranslation convert(HabitTranslationDto habitTranslationDto) { .build(); } + /** + * Additional method that build {@link HabitTranslation} from + * {@link HabitTranslationDto} but from nameUa, descriptionUa, habitItemUa + * fields if they not null. + * + * @param habitTranslationDto {@link HabitTranslationDto} + * @return {@link HabitTranslation} + * + * @author Chernenko Vitaliy + */ + public HabitTranslation convertUa(HabitTranslationDto habitTranslationDto) { + HabitTranslation habitTranslation = new HabitTranslation(); + habitTranslation + .setName(ObjectUtils.defaultIfNull(habitTranslationDto.getNameUa(), habitTranslationDto.getName())); + habitTranslation.setDescription( + ObjectUtils.defaultIfNull(habitTranslationDto.getDescriptionUa(), habitTranslationDto.getDescription())); + habitTranslation.setHabitItem( + ObjectUtils.defaultIfNull(habitTranslationDto.getHabitItemUa(), habitTranslationDto.getHabitItem())); + + return habitTranslation; + } + /** * Method that build {@link List} of {@link HabitTranslation} from {@link List} * of {@link HabitTranslationDto}. @@ -29,4 +53,22 @@ protected HabitTranslation convert(HabitTranslationDto habitTranslationDto) { public List mapAllToList(List dtoList) { return dtoList.stream().map(this::convert).collect(Collectors.toList()); } + + /** + * Method that build {@link List} of {@link HabitTranslation} from {@link List} + * of {@link HabitTranslationDto} and {@link String} language. + * + * @param dtoList {@link List} of {@link HabitTranslationDto} + * @param language {@link String} + * + * @return {@link List} of {@link HabitTranslation} + * + * @author Chernenko Vitaliy + */ + public List mapAllToList(List dtoList, String language) { + if (AppConstant.LANGUAGE_CODE_UA.equals(language)) { + return dtoList.stream().map(this::convertUa).collect(Collectors.toList()); + } + return dtoList.stream().map(this::convert).collect(Collectors.toList()); + } } diff --git a/service/src/main/java/greencity/service/HabitServiceImpl.java b/service/src/main/java/greencity/service/HabitServiceImpl.java index 56db8854c8..b6dadb17a6 100644 --- a/service/src/main/java/greencity/service/HabitServiceImpl.java +++ b/service/src/main/java/greencity/service/HabitServiceImpl.java @@ -497,21 +497,24 @@ private void updateHabitTranslationsForCustomHabit(CustomHabitDtoRequest habitDt } private void saveHabitTranslationListsToHabitTranslationRepo(CustomHabitDtoRequest habitDto, Habit habit) { - List habitTranslationListForUa = mapHabitTranslationFromAddCustomHabitDtoRequest(habitDto); + List habitTranslationListForUa = + mapHabitTranslationFromAddCustomHabitDtoRequest(habitDto, AppConstant.LANGUAGE_CODE_UA); habitTranslationListForUa.forEach(habitTranslation -> habitTranslation.setHabit(habit)); habitTranslationListForUa.forEach(habitTranslation -> habitTranslation.setLanguage( - languageRepo.findByCode("ua").orElseThrow(NoSuchElementException::new))); + languageRepo.findByCode(AppConstant.LANGUAGE_CODE_UA).orElseThrow(NoSuchElementException::new))); habitTranslationRepo.saveAll(habitTranslationListForUa); - List habitTranslationListForEn = mapHabitTranslationFromAddCustomHabitDtoRequest(habitDto); + List habitTranslationListForEn = + mapHabitTranslationFromAddCustomHabitDtoRequest(habitDto, AppConstant.DEFAULT_LANGUAGE_CODE); habitTranslationListForEn.forEach(habitTranslation -> habitTranslation.setHabit(habit)); habitTranslationListForEn.forEach(habitTranslation -> habitTranslation.setLanguage( - languageRepo.findByCode("en").orElseThrow(NoSuchElementException::new))); + languageRepo.findByCode(AppConstant.DEFAULT_LANGUAGE_CODE).orElseThrow(NoSuchElementException::new))); habitTranslationRepo.saveAll(habitTranslationListForEn); } - private List mapHabitTranslationFromAddCustomHabitDtoRequest(CustomHabitDtoRequest habitDto) { - return habitTranslationMapper.mapAllToList(habitDto.getHabitTranslations()); + private List mapHabitTranslationFromAddCustomHabitDtoRequest(CustomHabitDtoRequest habitDto, + String language) { + return habitTranslationMapper.mapAllToList(habitDto.getHabitTranslations(), language); } private void setTagsIdsToHabit(CustomHabitDtoRequest habitDto, Habit habit) { diff --git a/service/src/test/java/greencity/ModelUtils.java b/service/src/test/java/greencity/ModelUtils.java index ce797668be..3863686b14 100644 --- a/service/src/test/java/greencity/ModelUtils.java +++ b/service/src/test/java/greencity/ModelUtils.java @@ -276,9 +276,12 @@ public class ModelUtils { public static ZonedDateTime zonedDateTime = ZonedDateTime.now(); public static LocalDateTime localDateTime = LocalDateTime.now(); public static String habitTranslationName = "use shopper"; + public static String habitTranslationNameUa = "Назва звички українською"; public static String habitTranslationDescription = "Description"; + public static String habitTranslationDescriptionUa = "Опис звички українською"; public static String toDoListText = "buy a shopper"; public static String habitItem = "Item"; + public static String habitItemUa = "Айтем звички українською"; public static String habitDefaultImage = "img/habit-default.png"; public static AddEventDtoRequest addEventDtoRequest = AddEventDtoRequest.builder() .datesLocations(List.of(EventDateLocationDto.builder() @@ -2577,6 +2580,18 @@ public static HabitTranslationDto getHabitTranslationDto() { .build(); } + public static HabitTranslationDto getHabitTranslationDtoEnAndUa() { + return HabitTranslationDto.builder() + .description(habitTranslationDescription) + .habitItem(habitItem) + .name(habitTranslationName) + .languageCode("en") + .nameUa(habitTranslationNameUa) + .descriptionUa(habitTranslationDescriptionUa) + .habitItemUa(habitItemUa) + .build(); + } + public static HabitTranslation getHabitTranslationForServiceTest() { return HabitTranslation.builder() .id(1L) diff --git a/service/src/test/java/greencity/mapping/HabitTranslationMapperTests.java b/service/src/test/java/greencity/mapping/HabitTranslationMapperTests.java index f0b2ba0eb3..e76875cac2 100644 --- a/service/src/test/java/greencity/mapping/HabitTranslationMapperTests.java +++ b/service/src/test/java/greencity/mapping/HabitTranslationMapperTests.java @@ -1,13 +1,13 @@ package greencity.mapping; import greencity.ModelUtils; +import greencity.constant.AppConstant; import greencity.dto.habittranslation.HabitTranslationDto; import greencity.entity.HabitTranslation; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.junit.jupiter.MockitoExtension; - import java.util.List; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -29,6 +29,18 @@ void convertTest() { assertEquals(expected, habitTranslationMapper.convert(habitTranslationDto)); } + @Test + void convertUaWithValidHabitTranslationDtoSucceedsTest() { + HabitTranslationDto habitTranslationDto = ModelUtils.getHabitTranslationDtoEnAndUa(); + + HabitTranslation expected = HabitTranslation.builder() + .description(habitTranslationDto.getDescriptionUa()) + .habitItem(habitTranslationDto.getHabitItemUa()) + .name(habitTranslationDto.getNameUa()) + .build(); + assertEquals(expected, habitTranslationMapper.convertUa(habitTranslationDto)); + } + @Test void mapAllToListTest() { HabitTranslationDto habitTranslationDto = ModelUtils.getHabitTranslationDto(); @@ -42,4 +54,52 @@ void mapAllToListTest() { List expectedList = List.of(expected); assertEquals(expectedList, habitTranslationMapper.mapAllToList(habitTranslationDtoList)); } + + @Test + void mapAllToListWithEnLanguageReturnsListTest() { + HabitTranslationDto habitTranslationDto = ModelUtils.getHabitTranslationDtoEnAndUa(); + List habitTranslationDtoList = List.of(habitTranslationDto); + + HabitTranslation expected = HabitTranslation.builder() + .description(habitTranslationDto.getDescription()) + .habitItem(habitTranslationDto.getHabitItem()) + .name(habitTranslationDto.getName()) + .build(); + List expectedList = List.of(expected); + + assertEquals(expectedList, + habitTranslationMapper.mapAllToList(habitTranslationDtoList, AppConstant.DEFAULT_LANGUAGE_CODE)); + } + + @Test + void mapAllToListWithUaLanguageReturnsListTest() { + HabitTranslationDto habitTranslationDto = ModelUtils.getHabitTranslationDtoEnAndUa(); + List habitTranslationDtoList = List.of(habitTranslationDto); + + HabitTranslation expected = HabitTranslation.builder() + .description(habitTranslationDto.getDescriptionUa()) + .habitItem(habitTranslationDto.getHabitItemUa()) + .name(habitTranslationDto.getNameUa()) + .build(); + List expectedList = List.of(expected); + + assertEquals(expectedList, + habitTranslationMapper.mapAllToList(habitTranslationDtoList, AppConstant.LANGUAGE_CODE_UA)); + } + + @Test + void mapAllToListWithUaCodeButEmptyUaFieldsReturnListTest() { + HabitTranslationDto habitTranslationDto = ModelUtils.getHabitTranslationDto(); + List habitTranslationDtoList = List.of(habitTranslationDto); + + HabitTranslation expected = HabitTranslation.builder() + .description(habitTranslationDto.getDescription()) + .habitItem(habitTranslationDto.getHabitItem()) + .name(habitTranslationDto.getName()) + .build(); + List expectedList = List.of(expected); + + assertEquals(expectedList, + habitTranslationMapper.mapAllToList(habitTranslationDtoList, AppConstant.LANGUAGE_CODE_UA)); + } } diff --git a/service/src/test/java/greencity/service/HabitServiceImplTest.java b/service/src/test/java/greencity/service/HabitServiceImplTest.java index 5c954a0ab4..ff809026fc 100644 --- a/service/src/test/java/greencity/service/HabitServiceImplTest.java +++ b/service/src/test/java/greencity/service/HabitServiceImplTest.java @@ -633,7 +633,9 @@ void addCustomHabitTestWithImagePathInDto() throws IOException { when(userRepo.findByEmail(user.getEmail())).thenReturn(Optional.of(user)); when(habitRepo.save(customHabitMapper.convert(addCustomHabitDtoRequest))).thenReturn(habit); when(tagsRepo.findById(20L)).thenReturn(Optional.of(tag)); - when(habitTranslationMapper.mapAllToList(List.of(habitTranslationDto))) + when(habitTranslationMapper.mapAllToList(List.of(habitTranslationDto), "ua")) + .thenReturn(List.of(habitTranslationUa)); + when(habitTranslationMapper.mapAllToList(List.of(habitTranslationDto), "en")) .thenReturn(List.of(habitTranslationUa)); when(languageRepo.findByCode("ua")).thenReturn(Optional.of(languageUa)); when(languageRepo.findByCode("en")).thenReturn(Optional.of(languageEn)); @@ -655,7 +657,8 @@ void addCustomHabitTestWithImagePathInDto() throws IOException { verify(habitRepo).save(customHabitMapper.convert(addCustomHabitDtoRequest)); verify(customHabitMapper, times(3)).convert(addCustomHabitDtoRequest); verify(tagsRepo).findById(20L); - verify(habitTranslationMapper, times(2)).mapAllToList(List.of(habitTranslationDto)); + verify(habitTranslationMapper, times(1)).mapAllToList(List.of(habitTranslationDto), "ua"); + verify(habitTranslationMapper, times(1)).mapAllToList(List.of(habitTranslationDto), "en"); verify(languageRepo, times(2)).findByCode(anyString()); verify(customToDoListItemRepo).findAllByUserIdAndHabitId(1L, 1L); verify(customToDoListMapper).mapAllToList(anyList()); @@ -706,8 +709,10 @@ void addCustomHabitTestWithImageFile() throws IOException { when(languageRepo.findByCode("ua")).thenReturn(Optional.of(languageUa)); when(languageRepo.findByCode("en")).thenReturn(Optional.of(languageEn)); when(customToDoListItemRepo.findAllByUserIdAndHabitId(1L, 1L)).thenReturn(List.of(customToDoListItem)); - when(customToDoListMapper.mapAllToList(List.of(customToDoListItemResponseDto))) - .thenReturn(List.of(customToDoListItem)); + when(habitTranslationMapper.mapAllToList(List.of(habitTranslationDto), "ua")) + .thenReturn(List.of(habitTranslationUa)); + when(habitTranslationMapper.mapAllToList(List.of(habitTranslationDto), "en")) + .thenReturn(List.of(habitTranslationUa)); when(modelMapper.map(habit, CustomHabitDtoResponse.class)).thenReturn(addCustomHabitDtoResponse); when(customToDoListResponseDtoMapper.mapAllToList(List.of(customToDoListItem))) .thenReturn(List.of(customToDoListItemResponseDto)); @@ -723,7 +728,8 @@ void addCustomHabitTestWithImageFile() throws IOException { verify(habitRepo).save(customHabitMapper.convert(addCustomHabitDtoRequest)); verify(customHabitMapper, times(3)).convert(addCustomHabitDtoRequest); verify(tagsRepo).findById(20L); - verify(habitTranslationMapper, times(2)).mapAllToList(List.of(habitTranslationDto)); + verify(habitTranslationMapper, times(1)).mapAllToList(List.of(habitTranslationDto), "ua"); + verify(habitTranslationMapper, times(1)).mapAllToList(List.of(habitTranslationDto), "en"); verify(languageRepo, times(2)).findByCode(anyString()); verify(customToDoListItemRepo).findAllByUserIdAndHabitId(1L, 1L); verify(customToDoListMapper).mapAllToList(anyList()); @@ -769,7 +775,9 @@ void addCustomHabitTest2() throws IOException { when(userRepo.findByEmail(user.getEmail())).thenReturn(Optional.of(user)); when(habitRepo.save(customHabitMapper.convert(addCustomHabitDtoRequest))).thenReturn(habit); when(tagsRepo.findById(20L)).thenReturn(Optional.of(tag)); - when(habitTranslationMapper.mapAllToList(List.of(habitTranslationDto))) + when(habitTranslationMapper.mapAllToList(List.of(habitTranslationDto), "ua")) + .thenReturn(List.of(habitTranslationUa)); + when(habitTranslationMapper.mapAllToList(List.of(habitTranslationDto), "en")) .thenReturn(List.of(habitTranslationUa)); when(languageRepo.findByCode("ua")).thenReturn(Optional.of(languageUa)); when(languageRepo.findByCode("en")).thenReturn(Optional.of(languageEn)); @@ -791,7 +799,8 @@ void addCustomHabitTest2() throws IOException { verify(habitRepo).save(customHabitMapper.convert(addCustomHabitDtoRequest)); verify(customHabitMapper, times(3)).convert(addCustomHabitDtoRequest); verify(tagsRepo).findById(20L); - verify(habitTranslationMapper, times(2)).mapAllToList(List.of(habitTranslationDto)); + verify(habitTranslationMapper, times(1)).mapAllToList(List.of(habitTranslationDto), "ua"); + verify(habitTranslationMapper, times(1)).mapAllToList(List.of(habitTranslationDto), "en"); verify(languageRepo, times(2)).findByCode(anyString()); verify(customToDoListItemRepo).findAllByUserIdAndHabitId(1L, 1L); verify(customToDoListMapper).mapAllToList(anyList()); @@ -821,7 +830,9 @@ void addCustomHabitNoSuchElementExceptionWithNotExistingLanguageCodeTestUa() thr when(userRepo.findByEmail(user.getEmail())).thenReturn(Optional.of(user)); when(habitRepo.save(customHabitMapper.convert(addCustomHabitDtoRequest))).thenReturn(habit); when(tagsRepo.findById(20L)).thenReturn(Optional.of(tag)); - when(habitTranslationMapper.mapAllToList(List.of(habitTranslationDto))) + when(habitTranslationMapper.mapAllToList(addCustomHabitDtoRequest.getHabitTranslations(), "ua")) + .thenReturn(List.of(habitTranslation)); + when(habitTranslationMapper.mapAllToList(addCustomHabitDtoRequest.getHabitTranslations(), "en")) .thenReturn(List.of(habitTranslation)); when(languageRepo.findByCode("ua")).thenReturn(Optional.empty()); @@ -832,7 +843,8 @@ void addCustomHabitNoSuchElementExceptionWithNotExistingLanguageCodeTestUa() thr verify(habitRepo).save(customHabitMapper.convert(addCustomHabitDtoRequest)); verify(customHabitMapper, times(3)).convert(addCustomHabitDtoRequest); verify(tagsRepo).findById(20L); - verify(habitTranslationMapper).mapAllToList(addCustomHabitDtoRequest.getHabitTranslations()); + verify(habitTranslationMapper, times(1)).mapAllToList(List.of(habitTranslationDto), "ua"); + verify(habitTranslationMapper, times(0)).mapAllToList(List.of(habitTranslationDto), "en"); verify(languageRepo).findByCode(anyString()); } @@ -856,7 +868,9 @@ void addCustomHabitNoSuchElementExceptionWithNotExistingLanguageCodeEn() throws when(userRepo.findByEmail(user.getEmail())).thenReturn(Optional.of(user)); when(habitRepo.save(customHabitMapper.convert(addCustomHabitDtoRequest))).thenReturn(habit); when(tagsRepo.findById(20L)).thenReturn(Optional.of(tag)); - when(habitTranslationMapper.mapAllToList(List.of(habitTranslationDto))) + when(habitTranslationMapper.mapAllToList(addCustomHabitDtoRequest.getHabitTranslations(), "ua")) + .thenReturn(List.of(habitTranslationUa)); + when(habitTranslationMapper.mapAllToList(addCustomHabitDtoRequest.getHabitTranslations(), "en")) .thenReturn(List.of(habitTranslationUa)); when(languageRepo.findByCode("ua")).thenReturn(Optional.of(languageUa)); when(languageRepo.findByCode("en")).thenReturn(Optional.empty()); @@ -869,7 +883,8 @@ void addCustomHabitNoSuchElementExceptionWithNotExistingLanguageCodeEn() throws verify(customHabitMapper, times(3)).convert(addCustomHabitDtoRequest); verify(tagsRepo).findById(20L); - verify(habitTranslationMapper, times(2)).mapAllToList(addCustomHabitDtoRequest.getHabitTranslations()); + verify(habitTranslationMapper, times(1)).mapAllToList(List.of(habitTranslationDto), "ua"); + verify(habitTranslationMapper, times(1)).mapAllToList(List.of(habitTranslationDto), "en"); verify(languageRepo, times(2)).findByCode(anyString()); }