Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Endpoint achievements #6552

Merged
merged 17 commits into from
Oct 12, 2023
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,41 @@ 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(achievementRepo.findAll()).thenReturn(Arrays.asList(ModelUtils.getAchievement()));
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]", "UNACHIEVED");
assertTrue(findAllResult.isEmpty());
verify(userService).findByEmail("[email protected]");
verify(modelMapper).map(ModelUtils.getUserVO(), User.class);
verify(userAchievementRepo).getUserAchievementByUserId(anyLong());
verify(modelMapper, times(2)).map(ModelUtils.getAchievement(), AchievementVO.class);
}

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