diff --git a/core/src/main/java/greencity/controller/AchievementController.java b/core/src/main/java/greencity/controller/AchievementController.java index fbe5af16e6..be51725f1f 100644 --- a/core/src/main/java/greencity/controller/AchievementController.java +++ b/core/src/main/java/greencity/controller/AchievementController.java @@ -5,15 +5,18 @@ import greencity.dto.achievement.AchievementVO; import greencity.service.AchievementService; import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; import io.swagger.annotations.ApiResponse; import io.swagger.annotations.ApiResponses; +import java.security.Principal; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; +import springfox.documentation.annotations.ApiIgnore; @RestController @RequestMapping("/achievements") @@ -33,14 +36,18 @@ public AchievementController(AchievementService achievementService) { * * @return list of {@link AchievementDTO} */ - @ApiOperation(value = "Get all achievements.") + @ApiOperation(value = "Get all achievements by type.") @ApiResponses(value = { @ApiResponse(code = 200, message = HttpStatuses.OK), @ApiResponse(code = 400, message = HttpStatuses.BAD_REQUEST), @ApiResponse(code = 401, message = HttpStatuses.UNAUTHORIZED), }) @GetMapping("") - public ResponseEntity> getAll() { - return ResponseEntity.status(HttpStatus.OK).body(achievementService.findAll()); + public ResponseEntity> getAll(@ApiIgnore Principal principal, + @ApiParam(value = "Available values : ACHIEVED, UNACHIEVED." + + " Leave this field empty if you need items with any status") @RequestParam( + required = false) String achievementStatus) { + return ResponseEntity.status(HttpStatus.OK) + .body(achievementService.findAllByType(principal.getName(), achievementStatus)); } } diff --git a/core/src/test/java/greencity/controller/AchievementControllerTest.java b/core/src/test/java/greencity/controller/AchievementControllerTest.java index f0dc6d5727..6a662dd4dc 100644 --- a/core/src/test/java/greencity/controller/AchievementControllerTest.java +++ b/core/src/test/java/greencity/controller/AchievementControllerTest.java @@ -1,6 +1,7 @@ package greencity.controller; import greencity.enums.AchievementCategoryType; +import greencity.repository.AchievementRepo; import greencity.service.AchievementService; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -14,6 +15,10 @@ import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import java.security.Principal; + +import static greencity.ModelUtils.getPrincipal; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.verify; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; @@ -24,6 +29,7 @@ class AchievementControllerTest { private static final String achievementLink = "/achievements"; private MockMvc mockMvc; + private final Principal principal = getPrincipal(); @InjectMocks private AchievementController achievementController; @@ -40,8 +46,35 @@ void setup() { @Test void findAllTest() throws Exception { - mockMvc.perform(get(achievementLink)).andExpect(status().isOk()); - verify(achievementService).findAll(); + mockMvc.perform(get(achievementLink).principal(principal)).andExpect(status().isOk()); + verify(achievementService).findAllByType("test@gmail.com", null); + } + + @Test + void findAllAchievedTest() throws Exception { + mockMvc.perform(get(achievementLink).principal(principal).param("achievementStatus", "ACHIEVED")) + .andExpect(status().isOk()); + verify(achievementService).findAllByType("test@gmail.com", "ACHIEVED"); + } + + @Test + void findAllUnAchievedTest() throws Exception { + mockMvc.perform(get(achievementLink).principal(principal).param("achievementStatus", "UNACHIEVED")) + .andExpect(status().isOk()); + verify(achievementService).findAllByType("test@gmail.com", "UNACHIEVED"); + } + + @Test + void findAllAchievedIgnoreCaseTest() throws Exception { + mockMvc.perform(get(achievementLink).principal(principal).param("achievementStatus", "AchieVED")) + .andExpect(status().isOk()); + verify(achievementService).findAllByType("test@gmail.com", "AchieVED"); } + @Test + void findAllUnAchievedIgnoreCaseTest() throws Exception { + mockMvc.perform(get(achievementLink).principal(principal).param("achievementStatus", "unAchieVED")) + .andExpect(status().isOk()); + verify(achievementService).findAllByType("test@gmail.com", "unAchieVED"); + } } diff --git a/dao/src/main/java/greencity/repository/AchievementRepo.java b/dao/src/main/java/greencity/repository/AchievementRepo.java index ef1c027eb4..9fa0d7bdff 100644 --- a/dao/src/main/java/greencity/repository/AchievementRepo.java +++ b/dao/src/main/java/greencity/repository/AchievementRepo.java @@ -7,6 +7,7 @@ import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; +import java.util.List; import java.util.Optional; @Repository @@ -35,4 +36,17 @@ public interface AchievementRepo extends JpaRepository { * @author Orest Mamchuk */ Optional findByAchievementCategoryIdAndCondition(Long achievementCategoryId, Integer condition); + + /** + * Searches for achievements that have not yet been achieved by the specified + * user. + * + * @param userId The ID of the user for whom to find unachieved achievements. + * @return A list of achievements that the user has not yet achieved. + */ + @Query(value = "SELECT * from achievements " + + "where id not in (select achievement_id " + + " from user_achievements " + + " where user_id = :userId)", nativeQuery = true) + List searchAchievementsUnAchieved(Long userId); } diff --git a/service-api/src/main/java/greencity/service/AchievementService.java b/service-api/src/main/java/greencity/service/AchievementService.java index 37615be645..f6577fad26 100644 --- a/service-api/src/main/java/greencity/service/AchievementService.java +++ b/service-api/src/main/java/greencity/service/AchievementService.java @@ -9,13 +9,6 @@ import java.util.List; public interface AchievementService { - /** - * Method for finding all the achievements. - * - * @return list of all{@link AchievementDTO}. - */ - List findAll(); - /** * Find {@link AchievementVO} for management by page . * @@ -94,4 +87,17 @@ public interface AchievementService { */ void calculateAchievements(Long id, AchievementCategoryType achievementCategory, AchievementAction achievementAction); + + /** + * Retrieves a list of achievements based on the given type and the principal's + * email. + * + * @param principalEmail The email of the principal (usually the logged-in + * user) for whom the achievements need to be fetched. + * @param achievementStatus The status of the achievements to filter by (e.g., + * "ACHIEVED", "UNACHIEVED"). + * @return List AchievementVO Returns a list of achievements matching the given + * criteria. + */ + List findAllByType(String principalEmail, String achievementStatus); } diff --git a/service/src/main/java/greencity/service/AchievementServiceImpl.java b/service/src/main/java/greencity/service/AchievementServiceImpl.java index 75a2e7a2fe..b174cec743 100644 --- a/service/src/main/java/greencity/service/AchievementServiceImpl.java +++ b/service/src/main/java/greencity/service/AchievementServiceImpl.java @@ -2,7 +2,6 @@ import greencity.achievement.AchievementCalculation; import greencity.client.RestClient; -import greencity.constant.CacheConstants; import greencity.constant.ErrorMessage; import greencity.dto.PageableAdvancedDto; import greencity.dto.achievement.AchievementManagementDto; @@ -15,6 +14,7 @@ import greencity.entity.Achievement; import greencity.entity.AchievementCategory; +import greencity.entity.User; import greencity.enums.AchievementCategoryType; import greencity.enums.AchievementAction; import greencity.exception.exceptions.NotDeletedException; @@ -22,12 +22,13 @@ import greencity.exception.exceptions.NotUpdatedException; import greencity.repository.AchievementRepo; +import java.util.Optional; import java.util.List; import java.util.stream.Collectors; +import greencity.repository.UserAchievementRepo; import lombok.AllArgsConstructor; import org.modelmapper.ModelMapper; -import org.springframework.cache.annotation.Cacheable; import org.springframework.cache.annotation.EnableCaching; import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.data.domain.Page; @@ -46,6 +47,9 @@ public class AchievementServiceImpl implements AchievementService { private final UserActionService userActionService; private AchievementCalculation achievementCalculation; private UserService userService; + private final UserAchievementRepo userAchievementRepo; + private static final String ACHIEVED = "ACHIEVED"; + private static final String UNACHIEVED = "UNACHIEVED"; /** * {@inheritDoc} @@ -60,7 +64,6 @@ public AchievementVO save(AchievementPostDto achievementPostDto) { achievement.setTitle(achievementPostDto.getTitle()); achievement.setName(achievementPostDto.getName()); achievement.setNameEng(achievementPostDto.getNameEng()); - achievement.setAchievementCategory(modelMapper.map(achievementCategoryVO, AchievementCategory.class)); AchievementVO achievementVO = modelMapper.map(achievementRepo.save(achievement), AchievementVO.class); UserAchievementVO userAchievementVO = new UserAchievementVO(); @@ -86,11 +89,19 @@ public AchievementVO save(AchievementPostDto achievementPostDto) { /** * {@inheritDoc} * - * @author Yuriy Olkhovskyi + * @author Orest Mamchuk */ - @Cacheable(value = CacheConstants.ALL_ACHIEVEMENTS_CACHE_NAME) @Override - public List findAll() { + public PageableAdvancedDto findAll(Pageable page) { + Page pages = achievementRepo.findAll(page); + List achievementVOS = pages + .stream() + .map(achievement -> modelMapper.map(achievement, AchievementVO.class)) + .collect(Collectors.toList()); + return createPageable(achievementVOS, pages); + } + + private List findAll() { return achievementRepo.findAll() .stream() .map(achieve -> modelMapper.map(achieve, AchievementVO.class)) @@ -100,16 +111,34 @@ public List findAll() { /** * {@inheritDoc} * - * @author Orest Mamchuk + * @author Oksana Spodaryk */ @Override - public PageableAdvancedDto findAll(Pageable page) { - Page pages = achievementRepo.findAll(page); - List achievementVOS = pages + public List findAllByType(String principalEmail, String achievementStatus) { + User currentUser = modelMapper.map(userService.findByEmail(principalEmail), User.class); + Long userId = currentUser.getId(); + if (ACHIEVED.equalsIgnoreCase(achievementStatus)) { + return findAllAchieved(userId); + } else if (UNACHIEVED.equalsIgnoreCase(achievementStatus)) { + return achievementRepo.searchAchievementsUnAchieved(userId).stream() + .map(achieve -> modelMapper.map(achieve, AchievementVO.class)) + .collect(Collectors.toList()); + } + return findAll(); + } + + private List findAllAchieved(Long userId) { + List achievemnetsId = userAchievementRepo.getUserAchievementByUserId(userId) .stream() - .map(achievement -> modelMapper.map(achievement, AchievementVO.class)) + .map(userAchievement -> userAchievement.getAchievement().getId()) + .collect(Collectors.toList()); + return achievemnetsId + .stream() + .map(achievementRepo::findById) + .filter(Optional::isPresent) + .map(Optional::get) + .map(achieve -> modelMapper.map(achieve, AchievementVO.class)) .collect(Collectors.toList()); - return createPageable(achievementVOS, pages); } private PageableAdvancedDto createPageable(List achievementVOS, diff --git a/service/src/test/java/greencity/service/AchievementServiceImplTest.java b/service/src/test/java/greencity/service/AchievementServiceImplTest.java index 2c23fbcaef..21f2b71dc1 100644 --- a/service/src/test/java/greencity/service/AchievementServiceImplTest.java +++ b/service/src/test/java/greencity/service/AchievementServiceImplTest.java @@ -12,6 +12,7 @@ import greencity.entity.Achievement; import greencity.entity.AchievementCategory; +import greencity.entity.User; import greencity.enums.AchievementCategoryType; import greencity.enums.AchievementAction; import greencity.exception.exceptions.NotDeletedException; @@ -71,19 +72,24 @@ class AchievementServiceImplTest { @Test void findAllWithEmptyListTest() { + when(userService.findByEmail("email@gmail.com")).thenReturn(ModelUtils.getUserVO()); + when(modelMapper.map(ModelUtils.getUserVO(), User.class)).thenReturn(ModelUtils.getUser()); when(achievementRepo.findAll()).thenReturn(Collections.emptyList()); - List findAllResult = achievementService.findAll(); + List findAllResult = achievementService.findAllByType("email@gmail.com", ""); assertTrue(findAllResult.isEmpty()); } @Test void findAllWithOneValueInRepoTest() { Achievement achievement = ModelUtils.getAchievement(); + when(userService.findByEmail("email@gmail.com")).thenReturn(ModelUtils.getUserVO()); + when(modelMapper.map(ModelUtils.getUserVO(), User.class)).thenReturn(ModelUtils.getUser()); when(achievementRepo.findAll()) .thenReturn(Collections.singletonList(achievement)); when(modelMapper.map(achievement, AchievementVO.class)) .thenReturn(ModelUtils.getAchievementVO()); - List findAllResult = achievementService.findAll(); + when(userService.findByEmail("email@gmail.com")).thenReturn(ModelUtils.getUserVO()); + List findAllResult = achievementService.findAllByType("email@gmail.com", ""); assertEquals(1L, (long) findAllResult.get(0).getId()); } @@ -99,6 +105,38 @@ void findAllByPageableTest() { assertEquals(10, pageableAdvancedDto.getTotalElements()); } + @Test + void findAllACHIEVEDInRepoTest() { + when(userService.findByEmail("email@gmail.com")).thenReturn(ModelUtils.getUserVO()); + when(modelMapper.map(ModelUtils.getUserVO(), User.class)).thenReturn(ModelUtils.getUser()); + when(userAchievementRepo.getUserAchievementByUserId(anyLong())) + .thenReturn(Arrays.asList(ModelUtils.getUserAchievement())); + when(achievementRepo.findById(anyLong())).thenReturn(Optional.of(ModelUtils.getAchievement())); + when(modelMapper.map(ModelUtils.getAchievement(), AchievementVO.class)) + .thenReturn(ModelUtils.getAchievementVO()); + List findAllResult = achievementService.findAllByType("email@gmail.com", "ACHIEVED"); + assertEquals(1L, (long) findAllResult.get(0).getId()); + verify(userService).findByEmail("email@gmail.com"); + verify(modelMapper).map(ModelUtils.getUserVO(), User.class); + verify(userAchievementRepo).getUserAchievementByUserId(anyLong()); + verify(modelMapper).map(ModelUtils.getAchievement(), AchievementVO.class); + } + + @Test + void findAllUNACHIEVEDInRepoTest() { + when(userService.findByEmail("email@gmail.com")).thenReturn(ModelUtils.getUserVO()); + when(modelMapper.map(ModelUtils.getUserVO(), User.class)).thenReturn(ModelUtils.getUser()); + when(achievementRepo.searchAchievementsUnAchieved(anyLong())) + .thenReturn(Arrays.asList(ModelUtils.getAchievement())); + when(modelMapper.map(ModelUtils.getAchievement(), AchievementVO.class)) + .thenReturn(ModelUtils.getAchievementVO()); + List findAllResult = achievementService.findAllByType("email@gmail.com", "UNACHIEVED"); + assertEquals(1L, (long) findAllResult.get(0).getId()); + verify(userService).findByEmail("email@gmail.com"); + verify(modelMapper).map(ModelUtils.getUserVO(), User.class); + verify(achievementRepo).searchAchievementsUnAchieved(anyLong()); + } + @Test void saveTest() { Achievement achievement = ModelUtils.getAchievement();