Skip to content

Commit

Permalink
Merge pull request #6552 from ita-social-projects/endpoint-achievements
Browse files Browse the repository at this point in the history
Endpoint achievements
  • Loading branch information
ospodaryk authored Oct 12, 2023
2 parents a229e20 + 193df33 commit befd55a
Show file tree
Hide file tree
Showing 6 changed files with 153 additions and 26 deletions.
13 changes: 10 additions & 3 deletions core/src/main/java/greencity/controller/AchievementController.java
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand All @@ -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<List<AchievementVO>> getAll() {
return ResponseEntity.status(HttpStatus.OK).body(achievementService.findAll());
public ResponseEntity<List<AchievementVO>> 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));
}
}
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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;
Expand All @@ -24,6 +29,7 @@
class AchievementControllerTest {
private static final String achievementLink = "/achievements";
private MockMvc mockMvc;
private final Principal principal = getPrincipal();

@InjectMocks
private AchievementController achievementController;
Expand All @@ -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("[email protected]", null);
}

@Test
void findAllAchievedTest() throws Exception {
mockMvc.perform(get(achievementLink).principal(principal).param("achievementStatus", "ACHIEVED"))
.andExpect(status().isOk());
verify(achievementService).findAllByType("[email protected]", "ACHIEVED");
}

@Test
void findAllUnAchievedTest() throws Exception {
mockMvc.perform(get(achievementLink).principal(principal).param("achievementStatus", "UNACHIEVED"))
.andExpect(status().isOk());
verify(achievementService).findAllByType("[email protected]", "UNACHIEVED");
}

@Test
void findAllAchievedIgnoreCaseTest() throws Exception {
mockMvc.perform(get(achievementLink).principal(principal).param("achievementStatus", "AchieVED"))
.andExpect(status().isOk());
verify(achievementService).findAllByType("[email protected]", "AchieVED");
}

@Test
void findAllUnAchievedIgnoreCaseTest() throws Exception {
mockMvc.perform(get(achievementLink).principal(principal).param("achievementStatus", "unAchieVED"))
.andExpect(status().isOk());
verify(achievementService).findAllByType("[email protected]", "unAchieVED");
}
}
14 changes: 14 additions & 0 deletions dao/src/main/java/greencity/repository/AchievementRepo.java
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -35,4 +36,17 @@ public interface AchievementRepo extends JpaRepository<Achievement, Long> {
* @author Orest Mamchuk
*/
Optional<Achievement> 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<Achievement> searchAchievementsUnAchieved(Long userId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,6 @@
import java.util.List;

public interface AchievementService {
/**
* Method for finding all the achievements.
*
* @return list of all{@link AchievementDTO}.
*/
List<AchievementVO> findAll();

/**
* Find {@link AchievementVO} for management by page .
*
Expand Down Expand Up @@ -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<AchievementVO> findAllByType(String principalEmail, String achievementStatus);
}
53 changes: 41 additions & 12 deletions service/src/main/java/greencity/service/AchievementServiceImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -15,19 +14,21 @@
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;
import greencity.exception.exceptions.NotFoundException;
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;
Expand All @@ -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}
Expand All @@ -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();
Expand All @@ -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<AchievementVO> findAll() {
public PageableAdvancedDto<AchievementVO> findAll(Pageable page) {
Page<Achievement> pages = achievementRepo.findAll(page);
List<AchievementVO> achievementVOS = pages
.stream()
.map(achievement -> modelMapper.map(achievement, AchievementVO.class))
.collect(Collectors.toList());
return createPageable(achievementVOS, pages);
}

private List<AchievementVO> findAll() {
return achievementRepo.findAll()
.stream()
.map(achieve -> modelMapper.map(achieve, AchievementVO.class))
Expand All @@ -100,16 +111,34 @@ public List<AchievementVO> findAll() {
/**
* {@inheritDoc}
*
* @author Orest Mamchuk
* @author Oksana Spodaryk
*/
@Override
public PageableAdvancedDto<AchievementVO> findAll(Pageable page) {
Page<Achievement> pages = achievementRepo.findAll(page);
List<AchievementVO> achievementVOS = pages
public List<AchievementVO> 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<AchievementVO> findAllAchieved(Long userId) {
List<Long> 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<AchievementVO> createPageable(List<AchievementVO> achievementVOS,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -71,19 +72,24 @@ class AchievementServiceImplTest {

@Test
void findAllWithEmptyListTest() {
when(userService.findByEmail("[email protected]")).thenReturn(ModelUtils.getUserVO());
when(modelMapper.map(ModelUtils.getUserVO(), User.class)).thenReturn(ModelUtils.getUser());
when(achievementRepo.findAll()).thenReturn(Collections.emptyList());
List<AchievementVO> findAllResult = achievementService.findAll();
List<AchievementVO> findAllResult = achievementService.findAllByType("[email protected]", "");
assertTrue(findAllResult.isEmpty());
}

@Test
void findAllWithOneValueInRepoTest() {
Achievement achievement = ModelUtils.getAchievement();
when(userService.findByEmail("[email protected]")).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<AchievementVO> findAllResult = achievementService.findAll();
when(userService.findByEmail("[email protected]")).thenReturn(ModelUtils.getUserVO());
List<AchievementVO> findAllResult = achievementService.findAllByType("[email protected]", "");
assertEquals(1L, (long) findAllResult.get(0).getId());
}

Expand All @@ -99,6 +105,38 @@ void findAllByPageableTest() {
assertEquals(10, pageableAdvancedDto.getTotalElements());
}

@Test
void findAllACHIEVEDInRepoTest() {
when(userService.findByEmail("[email protected]")).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<AchievementVO> findAllResult = achievementService.findAllByType("[email protected]", "ACHIEVED");
assertEquals(1L, (long) findAllResult.get(0).getId());
verify(userService).findByEmail("[email protected]");
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 protected]")).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<AchievementVO> findAllResult = achievementService.findAllByType("[email protected]", "UNACHIEVED");
assertEquals(1L, (long) findAllResult.get(0).getId());
verify(userService).findByEmail("[email protected]");
verify(modelMapper).map(ModelUtils.getUserVO(), User.class);
verify(achievementRepo).searchAchievementsUnAchieved(anyLong());
}

@Test
void saveTest() {
Achievement achievement = ModelUtils.getAchievement();
Expand Down

0 comments on commit befd55a

Please sign in to comment.