Skip to content

Commit

Permalink
[GreenCity] Create endpoint for retrieving friends' (that are assign …
Browse files Browse the repository at this point in the history
…to habit) profile photos. #5805 (#5839)

* add getFriendsAssignedToHabitProfilePictures endpoint

* fix code smell

* refactor repo methods

* fix code

* fix code
  • Loading branch information
sergoliarnik committed May 24, 2023
1 parent 7608918 commit 939a36b
Show file tree
Hide file tree
Showing 9 changed files with 209 additions and 1 deletion.
3 changes: 2 additions & 1 deletion core/src/main/java/greencity/config/SecurityConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,8 @@ protected void configure(HttpSecurity http) throws Exception {
"/habit/assign/{habitAssignId}/allUserAndCustomList",
"/habit/assign/allUserAndCustomShoppingListsInprogress",
"/habit/assign/{habitAssignId}",
"/habit/tags/search")
"/habit/tags/search",
"/habit/{habitId}/friends/profile-pictures")
.hasAnyRole(USER, ADMIN, MODERATOR, UBS_EMPLOYEE)
.antMatchers(HttpMethod.POST,
"/category",
Expand Down
28 changes: 28 additions & 0 deletions core/src/main/java/greencity/controller/HabitController.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import greencity.annotations.ApiLocale;
import greencity.annotations.ApiPageableWithLocale;
import greencity.annotations.CurrentUser;
import greencity.annotations.ImageValidation;
import greencity.annotations.ValidLanguage;
import greencity.constant.HttpStatuses;
Expand All @@ -12,6 +13,8 @@
import greencity.dto.habit.HabitDto;
import greencity.dto.habit.HabitVO;
import greencity.dto.habittranslation.HabitTranslationDto;
import greencity.dto.user.UserProfilePictureDto;
import greencity.dto.user.UserVO;
import greencity.service.HabitService;
import greencity.service.TagsService;
import io.swagger.annotations.ApiOperation;
Expand Down Expand Up @@ -178,4 +181,29 @@ public ResponseEntity<AddCustomHabitDtoResponse> addCustomHabit(
.status(HttpStatus.CREATED)
.body(habitService.addCustomHabit(request, image, principal.getName()));
}

/**
* Retrieves the list of profile pictures of the user's friends (which have
* INPROGRESS assign to the habit).
*
* @param habitId {@link HabitVO} id.
* @param userVO {@link UserVO}.
* @return List of friends profile picture.
*/
@ApiOperation(
value = "Retrieves the list of profile pictures of the user's friends "
+ "(which have INPROGRESS assign to the habit).")
@ApiResponses(value = {
@ApiResponse(code = 200, message = HttpStatuses.OK),
@ApiResponse(code = 400, message = HttpStatuses.BAD_REQUEST),
@ApiResponse(code = 401, message = HttpStatuses.UNAUTHORIZED),
@ApiResponse(code = 404, message = HttpStatuses.NOT_FOUND),
})
@GetMapping("/{habitId}/friends/profile-pictures")
public ResponseEntity<List<UserProfilePictureDto>> getFriendsAssignedToHabitProfilePictures(
@PathVariable Long habitId,
@ApiIgnore @CurrentUser UserVO userVO) {
return ResponseEntity.status(HttpStatus.OK)
.body(habitService.getFriendsAssignedToHabitProfilePictures(habitId, userVO.getId()));
}
}
10 changes: 10 additions & 0 deletions core/src/test/java/greencity/controller/HabitControllerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -135,4 +135,14 @@ void postCustomHabit() throws Exception {
.andExpect(status().isCreated());
verify(habitService).addCustomHabit(dto, null, principal.getName());
}

@Test
void getFriendsAssignedToHabitProfilePictures() throws Exception {
Long habitId = 1L;

mockMvc.perform(get(habitLink + "/{habitId}/friends/profile-pictures", habitId))
.andExpect(status().isOk());

verify(habitService).getFriendsAssignedToHabitProfilePictures(habitId, null);
}
}
21 changes: 21 additions & 0 deletions dao/src/main/java/greencity/repository/UserRepo.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package greencity.repository;

import greencity.dto.habit.HabitVO;
import greencity.dto.user.UserManagementVO;
import greencity.dto.user.UserVO;
import greencity.entity.User;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
Expand Down Expand Up @@ -150,4 +152,23 @@ public interface UserRepo extends JpaRepository<User, Long>, JpaSpecificationExe
+ "(SELECT friend_id FROM users_friends "
+ "WHERE user_id = :friendId AND friend_id = :userId AND status = 'FRIEND'))")
Optional<User> findUserByIdAndByFriendId(Long userId, Long friendId);

/**
* Retrieves the list of the user's friends (which have INPROGRESS assign to the
* habit).
*
* @param habitId {@link HabitVO} id.
* @param userId {@link UserVO} id.
* @return List of friends.
*/
@Query(nativeQuery = true, value = "SELECT * FROM ((SELECT user_id FROM users_friends AS uf "
+ "WHERE uf.friend_id = :userId AND uf.status = 'FRIEND' AND "
+ "(SELECT count(*) FROM habit_assign ha WHERE ha.habit_id = :habitId AND ha.user_id = uf.user_id "
+ "AND ha.status = 'INPROGRESS') = 1) "
+ "UNION "
+ "(SELECT friend_id FROM users_friends AS uf "
+ "WHERE uf.user_id = :userId AND uf.status = 'FRIEND' AND "
+ "(SELECT count(*) FROM habit_assign ha WHERE ha.habit_id = :habitId AND ha.user_id = uf.friend_id "
+ "AND ha.status = 'INPROGRESS') = 1)) as ui JOIN users as u ON user_id = u.id")
List<User> getFriendsAssignedToHabit(Long userId, Long habitId);
}
13 changes: 13 additions & 0 deletions service-api/src/main/java/greencity/service/HabitService.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@
import greencity.dto.PageableDto;
import greencity.dto.habit.AddCustomHabitDtoRequest;
import greencity.dto.habit.AddCustomHabitDtoResponse;
import greencity.dto.habit.HabitVO;
import greencity.dto.shoppinglistitem.ShoppingListItemDto;
import greencity.dto.habit.HabitDto;
import greencity.dto.user.UserProfilePictureDto;
import greencity.dto.user.UserVO;
import org.springframework.data.domain.Pageable;
import org.springframework.web.multipart.MultipartFile;

Expand Down Expand Up @@ -99,4 +102,14 @@ public interface HabitService {
*/
AddCustomHabitDtoResponse addCustomHabit(AddCustomHabitDtoRequest addCustomHabitDtoRequest, MultipartFile image,
String userEmail);

/**
* Retrieves the list of profile pictures of the user's friends (which have
* INPROGRESS assign to the habit).
*
* @param habitId {@link HabitVO} id.
* @param userId {@link UserVO} id.
* @return List of friends' profile pictures.
*/
List<UserProfilePictureDto> getFriendsAssignedToHabitProfilePictures(Long habitId, Long userId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package greencity.mapping;

import greencity.dto.user.UserProfilePictureDto;
import greencity.entity.User;
import org.modelmapper.AbstractConverter;
import org.springframework.stereotype.Component;

@Component
public class UserProfilePictureDtoMapper extends AbstractConverter<User, UserProfilePictureDto> {
@Override
protected UserProfilePictureDto convert(User user) {
return UserProfilePictureDto.builder()
.id(user.getId())
.name(user.getName())
.profilePicturePath(user.getProfilePicturePath())
.build();
}
}
17 changes: 17 additions & 0 deletions service/src/main/java/greencity/service/HabitServiceImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import greencity.dto.habit.AddCustomHabitDtoResponse;
import greencity.dto.habit.HabitDto;
import greencity.dto.shoppinglistitem.ShoppingListItemDto;
import greencity.dto.user.UserProfilePictureDto;
import greencity.entity.CustomShoppingListItem;
import greencity.entity.Habit;
import greencity.entity.HabitTranslation;
Expand Down Expand Up @@ -235,4 +236,20 @@ private AddCustomHabitDtoResponse buildAddCustomHabitDtoResponse(Habit habit, Lo
.setHabitTranslations(habitTranslationDtoMapper.mapAllToList(habitTranslationRepo.findAllByHabit(habit)));
return response;
}

/**
* {@inheritDoc}
*/
@Override
public List<UserProfilePictureDto> getFriendsAssignedToHabitProfilePictures(Long habitId, Long userId) {
if (!userRepo.existsById(userId)) {
throw new NotFoundException(ErrorMessage.USER_NOT_FOUND_BY_ID + userId);
}
if (!habitRepo.existsById(habitId)) {
throw new NotFoundException(ErrorMessage.HABIT_NOT_FOUND_BY_ID + habitId);
}
List<User> users = userRepo.getFriendsAssignedToHabit(userId, habitId);
return users.stream().map(user -> modelMapper.map(user, UserProfilePictureDto.class))
.collect(Collectors.toList());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package greencity.mapping;

import greencity.ModelUtils;
import greencity.dto.user.UserProfilePictureDto;
import greencity.entity.User;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.springframework.test.context.junit.jupiter.SpringExtension;

import static org.junit.jupiter.api.Assertions.assertEquals;

@ExtendWith(SpringExtension.class)
class UserProfilePictureDtoMapperTest {
@InjectMocks
private UserProfilePictureDtoMapper mapper;

@Test
void convertTest() {
User user = ModelUtils.getUser();

UserProfilePictureDto expected = UserProfilePictureDto.builder()
.id(user.getId())
.name(user.getName())
.profilePicturePath(user.getProfilePicturePath())
.build();

assertEquals(expected, mapper.convert(user));
}
}
70 changes: 70 additions & 0 deletions service/src/test/java/greencity/service/HabitServiceImplTest.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
package greencity.service;

import greencity.ModelUtils;
import greencity.constant.ErrorMessage;
import greencity.dto.PageableDto;
import greencity.dto.habit.AddCustomHabitDtoRequest;
import greencity.dto.habit.AddCustomHabitDtoResponse;
import greencity.dto.habit.HabitDto;
import greencity.dto.habittranslation.HabitTranslationDto;
import greencity.dto.shoppinglistitem.CustomShoppingListItemResponseDto;
import greencity.dto.shoppinglistitem.ShoppingListItemDto;
import greencity.dto.user.UserProfilePictureDto;
import greencity.entity.CustomShoppingListItem;
import greencity.entity.Habit;
import greencity.entity.HabitTranslation;
Expand Down Expand Up @@ -51,13 +53,15 @@
import java.util.Set;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
Expand Down Expand Up @@ -528,4 +532,70 @@ void addCustomHabitThrowUserNotFoundException() {
verify(userRepo).findByEmail("user@gmail.com");
verify(customHabitMapper).convert(addCustomHabitDtoRequest);
}

@Test
void getFriendsAssignedToHabitProfilePicturesTest() {
Long habitId = 1L;
Long userId = 2L;
Long friendId = 3L;
User friend = ModelUtils.getUser();
friend.setId(friendId);
friend.setProfilePicturePath("test");
UserProfilePictureDto friendProfilePicture = UserProfilePictureDto.builder()
.id(friend.getId())
.name(friend.getName())
.profilePicturePath(friend.getProfilePicturePath())
.build();

when(userRepo.existsById(userId)).thenReturn(true);
when(habitRepo.existsById(habitId)).thenReturn(true);
when(userRepo.getFriendsAssignedToHabit(userId, habitId)).thenReturn(List.of(friend));
when(modelMapper.map(friend, UserProfilePictureDto.class)).thenReturn(friendProfilePicture);

List<UserProfilePictureDto> list = habitService.getFriendsAssignedToHabitProfilePictures(habitId, userId);
assertFalse(list.isEmpty());
assertEquals(friendProfilePicture, list.get(0));

verify(userRepo).existsById(userId);
verify(habitRepo).existsById(habitId);
verify(userRepo).getFriendsAssignedToHabit(userId, habitId);
verify(modelMapper).map(friend, UserProfilePictureDto.class);
}

@Test
void getFriendsAssignedToHabitProfilePicturesWhenUserNotFoundTest() {
Long habitId = 1L;
Long userId = 2L;

when(userRepo.existsById(userId)).thenReturn(false);

NotFoundException exception = assertThrows(NotFoundException.class,
() -> habitService.getFriendsAssignedToHabitProfilePictures(habitId, userId));

assertEquals(ErrorMessage.USER_NOT_FOUND_BY_ID + userId, exception.getMessage());

verify(userRepo).existsById(userId);
verify(habitRepo, never()).existsById(anyLong());
verify(userRepo, never()).getFriendsAssignedToHabit(anyLong(), anyLong());
verify(modelMapper, never()).map(any(), any());
}

@Test
void getFriendsAssignedToHabitProfilePicturesWhenHabitNotFoundTest() {
Long habitId = 1L;
Long userId = 2L;

when(userRepo.existsById(userId)).thenReturn(true);
when(habitRepo.existsById(userId)).thenReturn(false);

NotFoundException exception = assertThrows(NotFoundException.class,
() -> habitService.getFriendsAssignedToHabitProfilePictures(habitId, userId));

assertEquals(ErrorMessage.HABIT_NOT_FOUND_BY_ID + habitId, exception.getMessage());

verify(userRepo).existsById(userId);
verify(habitRepo).existsById(habitId);
verify(userRepo, never()).getFriendsAssignedToHabit(anyLong(), anyLong());
verify(modelMapper, never()).map(any(), any());
}
}

0 comments on commit 939a36b

Please sign in to comment.