Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
import java.security.Principal;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;
import lombok.AllArgsConstructor;
Expand Down Expand Up @@ -76,10 +77,22 @@ public ResponseEntity<PagedResponse<FeedbackStaffListItemDTO>> getStaffFeedbacks
pageCriteria.page(),
pageCriteria.pageSize());
var result = feedbackService.getStaffFeedbacks(statuses, activityId, pageCriteria);

var latestFeedbackIdsByDeclaredActivity = new HashMap<UUID, UUID>();
var content =
result.content().stream()
.map(
feedback -> {
var declaredActivityId = feedback.getDeclaredActivity().getId();
var latestFeedbackId =
latestFeedbackIdsByDeclaredActivity.computeIfAbsent(
declaredActivityId, id -> feedbackService.getLatestFeedback(id).getId());
return feedbackStaffListItemDTOMapper.toDTO(feedback, latestFeedbackId);
})
.toList();

return ResponseEntity.ok(
new PagedResponse<>(
result.content().stream().map(feedbackStaffListItemDTOMapper::toDTO).toList(),
PageInfoDTO.fromDomain(result.pageInfo())));
new PagedResponse<>(content, PageInfoDTO.fromDomain(result.pageInfo())));
}

@PreAuthorize("hasAuthority('feedback:history:read:contextual')")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

public record FeedbackStaffListItemDTO(
UUID id,
UUID latestFeedbackId,
UserInfoDTO student,
ActivityContentDTO activity,
@Schema(ref = "#/components/schemas/EFeedbackStatus") EFeedbackStatus status,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import fr.avenirsesr.portfolio.student.activity.application.adapter.dto.FeedbackStaffListItemDTO;
import fr.avenirsesr.portfolio.student.activity.domain.model.Feedback;
import fr.avenirsesr.portfolio.user.application.adapter.dto.UserInfoDTO;
import java.util.UUID;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;

Expand All @@ -13,9 +14,10 @@
uses = {ActivityContentDtoMapper.class})
public interface FeedbackStaffListItemDTOMapper {

@Mapping(source = "declaredActivity.student.user", target = "student")
@Mapping(source = "declaredActivity.activity", target = "activity")
FeedbackStaffListItemDTO toDTO(Feedback feedback);
@Mapping(source = "feedback.declaredActivity.student.user", target = "student")
@Mapping(source = "feedback.declaredActivity.activity", target = "activity")
@Mapping(source = "latestFeedbackId", target = "latestFeedbackId")
FeedbackStaffListItemDTO toDTO(Feedback feedback, UUID latestFeedbackId);

UserInfoDTO toUserInfoDTO(User user);
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,6 @@ Set<UUID> findAttachmentIdsUsedByTraceSnapshots(
List<UUID> declaredActivityIds, List<UUID> traceIds);

FeedbackDashboardData getFeedbackDashboard(UUID activityId);

Feedback getLatestFeedback(UUID declaredActivityId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -358,4 +358,9 @@ public FeedbackDashboardData getFeedbackDashboard(UUID activityId) {
return new FeedbackDashboardData(
newCount, pendingFeedbacks, processedFeedbacks, totalFeedbacks);
}

@Override
public Feedback getLatestFeedback(UUID declaredActivityId) {
return feedbackRepository.findAllByDeclaredActivityId(declaredActivityId).getFirst();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import fr.avenirsesr.portfolio.student.activity.application.adapter.mapper.StudentFeedbackItemListDTOMapper;
import fr.avenirsesr.portfolio.student.activity.domain.data.FeedbackDashboardData;
import fr.avenirsesr.portfolio.student.activity.domain.data.FeedbackData;
import fr.avenirsesr.portfolio.student.activity.domain.model.DeclaredActivity;
import fr.avenirsesr.portfolio.student.activity.domain.model.Feedback;
import fr.avenirsesr.portfolio.student.activity.domain.model.enums.EFeedbackStatus;
import fr.avenirsesr.portfolio.student.activity.domain.port.input.FeedbackService;
Expand Down Expand Up @@ -194,21 +195,36 @@ void should_delegate_to_service_with_correct_id_and_category() {
@Nested
class GetStaffFeedbacks {

private Feedback feedbackWithLatestId(UUID declaredActivityId, UUID latestFeedbackId) {
Feedback feedback = mock(Feedback.class);
DeclaredActivity declaredActivity = mock(DeclaredActivity.class);
when(feedback.getDeclaredActivity()).thenReturn(declaredActivity);
when(declaredActivity.getId()).thenReturn(declaredActivityId);

Feedback latestFeedback = mock(Feedback.class);
when(latestFeedback.getId()).thenReturn(latestFeedbackId);
when(feedbackService.getLatestFeedback(declaredActivityId)).thenReturn(latestFeedback);

return feedback;
}

@Test
void should_return_200_with_paged_result_when_no_filters() {
BddLogger.given("A logged-in staff with two feedbacks and no filter applied");

Feedback feedback1 = mock(Feedback.class);
Feedback feedback2 = mock(Feedback.class);
UUID latestFeedbackId1 = UUID.randomUUID();
UUID latestFeedbackId2 = UUID.randomUUID();
Feedback feedback1 = feedbackWithLatestId(UUID.randomUUID(), latestFeedbackId1);
Feedback feedback2 = feedbackWithLatestId(UUID.randomUUID(), latestFeedbackId2);
FeedbackStaffListItemDTO dto1 = mock(FeedbackStaffListItemDTO.class);
FeedbackStaffListItemDTO dto2 = mock(FeedbackStaffListItemDTO.class);

PagedResult<Feedback> pagedResult =
new PagedResult<>(List.of(feedback1, feedback2), new PageInfo(0, 8, 2));

when(feedbackService.getStaffFeedbacks(isNull(), isNull(), any())).thenReturn(pagedResult);
when(feedbackStaffListItemDTOMapper.toDTO(feedback1)).thenReturn(dto1);
when(feedbackStaffListItemDTOMapper.toDTO(feedback2)).thenReturn(dto2);
when(feedbackStaffListItemDTOMapper.toDTO(feedback1, latestFeedbackId1)).thenReturn(dto1);
when(feedbackStaffListItemDTOMapper.toDTO(feedback2, latestFeedbackId2)).thenReturn(dto2);

BddLogger.when("getStaffFeedbacks is called without any filter");
ResponseEntity<PagedResponse<FeedbackStaffListItemDTO>> response =
Expand All @@ -221,15 +237,16 @@ void should_return_200_with_paged_result_when_no_filters() {
assertThat(response.getBody().page().totalElements()).isEqualTo(2);

verify(feedbackService).getStaffFeedbacks(isNull(), isNull(), any());
verify(feedbackStaffListItemDTOMapper).toDTO(feedback1);
verify(feedbackStaffListItemDTOMapper).toDTO(feedback2);
verify(feedbackStaffListItemDTOMapper).toDTO(feedback1, latestFeedbackId1);
verify(feedbackStaffListItemDTOMapper).toDTO(feedback2, latestFeedbackId2);
}

@Test
void should_forward_statuses_filter_to_service() {
BddLogger.given("A logged-in staff requesting only IN_PROCESS feedbacks");

Feedback feedback = mock(Feedback.class);
UUID latestFeedbackId = UUID.randomUUID();
Feedback feedback = feedbackWithLatestId(UUID.randomUUID(), latestFeedbackId);
FeedbackStaffListItemDTO dto = mock(FeedbackStaffListItemDTO.class);

PagedResult<Feedback> pagedResult =
Expand All @@ -239,7 +256,7 @@ void should_forward_statuses_filter_to_service() {

when(feedbackService.getStaffFeedbacks(eq(statuses), isNull(), any()))
.thenReturn(pagedResult);
when(feedbackStaffListItemDTOMapper.toDTO(feedback)).thenReturn(dto);
when(feedbackStaffListItemDTOMapper.toDTO(feedback, latestFeedbackId)).thenReturn(dto);

BddLogger.when("getStaffFeedbacks is called with status=IN_PROCESS");
ResponseEntity<PagedResponse<FeedbackStaffListItemDTO>> response =
Expand All @@ -256,8 +273,10 @@ void should_forward_statuses_filter_to_service() {
void should_forward_multiple_statuses_filter_to_service() {
BddLogger.given("A logged-in staff requesting feedbacks with multiple statuses");

Feedback feedback1 = mock(Feedback.class);
Feedback feedback2 = mock(Feedback.class);
UUID latestFeedbackId1 = UUID.randomUUID();
UUID latestFeedbackId2 = UUID.randomUUID();
Feedback feedback1 = feedbackWithLatestId(UUID.randomUUID(), latestFeedbackId1);
Feedback feedback2 = feedbackWithLatestId(UUID.randomUUID(), latestFeedbackId2);
FeedbackStaffListItemDTO dto1 = mock(FeedbackStaffListItemDTO.class);
FeedbackStaffListItemDTO dto2 = mock(FeedbackStaffListItemDTO.class);

Expand All @@ -268,8 +287,8 @@ void should_forward_multiple_statuses_filter_to_service() {

when(feedbackService.getStaffFeedbacks(eq(statuses), isNull(), any()))
.thenReturn(pagedResult);
when(feedbackStaffListItemDTOMapper.toDTO(feedback1)).thenReturn(dto1);
when(feedbackStaffListItemDTOMapper.toDTO(feedback2)).thenReturn(dto2);
when(feedbackStaffListItemDTOMapper.toDTO(feedback1, latestFeedbackId1)).thenReturn(dto1);
when(feedbackStaffListItemDTOMapper.toDTO(feedback2, latestFeedbackId2)).thenReturn(dto2);

BddLogger.when("getStaffFeedbacks is called with multiple statuses");
ResponseEntity<PagedResponse<FeedbackStaffListItemDTO>> response =
Expand All @@ -289,15 +308,16 @@ void should_forward_activity_id_filter_to_service() {
BddLogger.given("A logged-in staff requesting feedbacks for a specific activity");

UUID activityId = UUID.randomUUID();
Feedback feedback = mock(Feedback.class);
UUID latestFeedbackId = UUID.randomUUID();
Feedback feedback = feedbackWithLatestId(UUID.randomUUID(), latestFeedbackId);
FeedbackStaffListItemDTO dto = mock(FeedbackStaffListItemDTO.class);

PagedResult<Feedback> pagedResult =
new PagedResult<>(List.of(feedback), new PageInfo(0, 8, 1));

when(feedbackService.getStaffFeedbacks(isNull(), eq(activityId), any()))
.thenReturn(pagedResult);
when(feedbackStaffListItemDTOMapper.toDTO(feedback)).thenReturn(dto);
when(feedbackStaffListItemDTOMapper.toDTO(feedback, latestFeedbackId)).thenReturn(dto);

BddLogger.when("getStaffFeedbacks is called with activityId");
ResponseEntity<PagedResponse<FeedbackStaffListItemDTO>> response =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1512,6 +1512,44 @@ void should_throw_UserIsNotStaffException_when_logged_in_user_is_not_staff() {
}
}

@Nested
class GetLatestFeedback {
@Test
void should_return_the_first_feedback_returned_by_the_repository() {
BddLogger.given(
"A declared activity with several feedbacks, the repository already sorting them by"
+ " createdAt descending");
UUID declaredActivityId = UUID.randomUUID();
Feedback latestFeedback = mock(Feedback.class);
Feedback olderFeedback = mock(Feedback.class);

when(feedbackRepository.findAllByDeclaredActivityId(declaredActivityId))
.thenReturn(List.of(latestFeedback, olderFeedback));

BddLogger.when("getLatestFeedback is called");
Feedback result = service.getLatestFeedback(declaredActivityId);

BddLogger.then("The first feedback of the repository result (the most recent) is returned");
assertThat(result).isEqualTo(latestFeedback);
}

@Test
void should_pass_the_declared_activity_id_to_the_repository() {
BddLogger.given("A declared activity ID");
UUID declaredActivityId = UUID.randomUUID();
Feedback feedback = mock(Feedback.class);

when(feedbackRepository.findAllByDeclaredActivityId(declaredActivityId))
.thenReturn(List.of(feedback));

BddLogger.when("getLatestFeedback is called");
service.getLatestFeedback(declaredActivityId);

BddLogger.then("The repository is called with the correct declaredActivityId");
verify(feedbackRepository).findAllByDeclaredActivityId(declaredActivityId);
}
}

@Nested
class GetFeedbackDashboardData {

Expand Down
Loading