Skip to content

Commit 7268e82

Browse files
committed
feat: 봉사자의 자신에게 온 쪽지 목록 확인 기능 구현
- 쿼리 메서드 생성 - 서비스 메서드 생성 - 응답 객체 생성 - 테스트 코드 작성및 검증 완료
1 parent 9b5d6ab commit 7268e82

File tree

9 files changed

+231
-18
lines changed

9 files changed

+231
-18
lines changed

src/main/java/com/somemore/note/controller/NoteQueryApiController.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.somemore.auth.annotation.CurrentUser;
44
import com.somemore.global.common.response.ApiResponse;
55
import com.somemore.note.repository.mapper.NoteReceiverViewForCenter;
6+
import com.somemore.note.repository.mapper.NoteReceiverViewForVolunteer;
67
import com.somemore.note.usecase.NoteQueryUseCase;
78
import io.swagger.v3.oas.annotations.Operation;
89
import io.swagger.v3.oas.annotations.tags.Tag;
@@ -31,4 +32,15 @@ public ApiResponse<Page<NoteReceiverViewForCenter>> getNotesByCenterId(@CurrentU
3132

3233
return ApiResponse.ok(200, response, "내 쪽지 조회 성공");
3334
}
35+
36+
@Secured("ROLE_VOLUNTEER")
37+
@Operation(summary = "봉사자의 자신에게 온 쪽지 조회")
38+
@GetMapping("/volunteer")
39+
public ApiResponse<Page<NoteReceiverViewForVolunteer>> getNotesByVolunteerId(@CurrentUser UUID volunteerId, Pageable pageable) {
40+
41+
Page<NoteReceiverViewForVolunteer> response = noteQueryUseCase.getNotesForVolunteer(volunteerId, pageable);
42+
43+
return ApiResponse.ok(200, response, "내 쪽지 조회 성공");
44+
}
45+
3446
}

src/main/java/com/somemore/note/repository/NoteRepository.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.somemore.note.domain.Note;
44
import com.somemore.note.repository.mapper.NoteReceiverViewForCenter;
5+
import com.somemore.note.repository.mapper.NoteReceiverViewForVolunteer;
56
import org.springframework.data.domain.Page;
67
import org.springframework.data.domain.Pageable;
78

@@ -10,4 +11,5 @@
1011
public interface NoteRepository {
1112
Note save(Note note);
1213
Page<NoteReceiverViewForCenter> findNotesByReceiverIsCenter(UUID centerId, Pageable pageable);
14+
Page<NoteReceiverViewForVolunteer> findNotesByReceiverIsVolunteer(UUID volunteerId, Pageable pageable);
1315
}

src/main/java/com/somemore/note/repository/NoteRepositoryImpl.java

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@
44
import com.querydsl.core.types.dsl.BooleanExpression;
55
import com.querydsl.jpa.impl.JPAQuery;
66
import com.querydsl.jpa.impl.JPAQueryFactory;
7+
import com.somemore.center.domain.QCenter;
78
import com.somemore.note.domain.Note;
89
import com.somemore.note.domain.QNote;
910
import com.somemore.note.repository.mapper.NoteReceiverViewForCenter;
11+
import com.somemore.note.repository.mapper.NoteReceiverViewForVolunteer;
1012
import com.somemore.volunteer.domain.QVolunteer;
1113
import lombok.RequiredArgsConstructor;
1214
import org.springframework.data.domain.Page;
@@ -26,6 +28,7 @@ public class NoteRepositoryImpl implements NoteRepository {
2628

2729
private static final QNote note = QNote.note;
2830
private static final QVolunteer volunteer = QVolunteer.volunteer;
31+
private static final QCenter center = QCenter.center;
2932

3033
@Override
3134
public Note save(Note note) {
@@ -64,4 +67,35 @@ public Page<NoteReceiverViewForCenter> findNotesByReceiverIsCenter(UUID centerId
6467
return PageableExecutionUtils.getPage(results, pageable, count::fetchOne);
6568
}
6669

70+
@Override
71+
public Page<NoteReceiverViewForVolunteer> findNotesByReceiverIsVolunteer(UUID volunteerId, Pageable pageable) {
72+
BooleanExpression activeCenter = center.deleted.eq(false);
73+
BooleanExpression condition = note.receiverId.eq(volunteerId)
74+
.and(note.deleted.eq(false));
75+
76+
List<NoteReceiverViewForVolunteer> results = queryFactory
77+
.select(Projections.constructor(
78+
NoteReceiverViewForVolunteer.class,
79+
note.id,
80+
note.title,
81+
center.id.as("senderId"),
82+
center.name.as("senderName"),
83+
note.isRead
84+
))
85+
.from(note)
86+
.join(center).on(note.senderId.eq(center.id).and(activeCenter))
87+
.where(condition)
88+
.offset(pageable.getOffset())
89+
.limit(pageable.getPageSize())
90+
.orderBy(note.createdAt.desc())
91+
.fetch();
92+
93+
JPAQuery<Long> count = queryFactory
94+
.select(note.count())
95+
.from(note)
96+
.where(condition);
97+
98+
return PageableExecutionUtils.getPage(results, pageable, count::fetchOne);
99+
}
100+
67101
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.somemore.note.repository.mapper;
2+
3+
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
4+
import com.fasterxml.jackson.databind.annotation.JsonNaming;
5+
import io.swagger.v3.oas.annotations.media.Schema;
6+
import lombok.Builder;
7+
8+
import java.util.UUID;
9+
10+
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
11+
@Builder
12+
public record NoteReceiverViewForVolunteer(
13+
@Schema(description = "쪽지 ID", example = "1111")
14+
Long id,
15+
@Schema(description = "쪽지 제목", example = "답변 드립니다..")
16+
String title,
17+
@Schema(description = "송신한 기관 id", example = "1342134-32423-35345")
18+
UUID senderId,
19+
@Schema(description = "송신 기관 닉네임", example = "서울 도서관")
20+
String senderName,
21+
@Schema(description = "읽음 여부", example = "true = 읽음, false = 안읽음")
22+
boolean isRead
23+
) {
24+
}

src/main/java/com/somemore/note/service/NoteQueryService.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.somemore.note.repository.NoteRepository;
44
import com.somemore.note.repository.mapper.NoteReceiverViewForCenter;
5+
import com.somemore.note.repository.mapper.NoteReceiverViewForVolunteer;
56
import com.somemore.note.usecase.NoteQueryUseCase;
67
import lombok.RequiredArgsConstructor;
78
import org.springframework.data.domain.Page;
@@ -22,4 +23,9 @@ public class NoteQueryService implements NoteQueryUseCase {
2223
public Page<NoteReceiverViewForCenter> getNotesForCenter(UUID centerId, Pageable pageable) {
2324
return noteRepository.findNotesByReceiverIsCenter(centerId, pageable);
2425
}
26+
27+
@Override
28+
public Page<NoteReceiverViewForVolunteer> getNotesForVolunteer(UUID volunteerId, Pageable pageable) {
29+
return noteRepository.findNotesByReceiverIsVolunteer(volunteerId, pageable);
30+
}
2531
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
package com.somemore.note.usecase;
22

33
import com.somemore.note.repository.mapper.NoteReceiverViewForCenter;
4+
import com.somemore.note.repository.mapper.NoteReceiverViewForVolunteer;
45
import org.springframework.data.domain.Page;
56
import org.springframework.data.domain.Pageable;
67

78
import java.util.UUID;
89

910
public interface NoteQueryUseCase {
1011
Page<NoteReceiverViewForCenter> getNotesForCenter(UUID centerId, Pageable pageable);
12+
Page<NoteReceiverViewForVolunteer> getNotesForVolunteer(UUID volunteerId, Pageable pageable);
1113
}

src/test/java/com/somemore/note/controller/NoteQueryApiControllerTest.java

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.somemore.ControllerTestSupport;
44
import com.somemore.WithMockCustomUser;
55
import com.somemore.note.repository.mapper.NoteReceiverViewForCenter;
6+
import com.somemore.note.repository.mapper.NoteReceiverViewForVolunteer;
67
import com.somemore.note.usecase.NoteQueryUseCase;
78
import org.junit.jupiter.api.DisplayName;
89
import org.junit.jupiter.api.Test;
@@ -74,4 +75,51 @@ void getNotesByCenterId() throws Exception {
7475
.andExpect(jsonPath("$.data.pageable.pageSize").value(6))
7576
.andExpect(jsonPath("$.data.totalElements").value(2));
7677
}
78+
79+
@DisplayName("봉사자는 자신에게 온 쪽지를 페이지 형태로 확인할 수 있다. (Controller)")
80+
@Test
81+
@WithMockCustomUser
82+
void getNotesByVolunteerId() throws Exception {
83+
// given
84+
Pageable pageable = PageRequest.of(0, 6);
85+
List<NoteReceiverViewForVolunteer> notes = List.of(
86+
NoteReceiverViewForVolunteer.builder()
87+
.id(1L)
88+
.title("답변 드립니다.")
89+
.senderName("서울 도서관")
90+
.isRead(false)
91+
.build(),
92+
NoteReceiverViewForVolunteer.builder()
93+
.id(2L)
94+
.title("요양원 입니다.")
95+
.senderName("서울 요양원")
96+
.isRead(true)
97+
.build()
98+
);
99+
Page<NoteReceiverViewForVolunteer> mockResponse = new PageImpl<>(notes, pageable, notes.size());
100+
101+
when(noteQueryUseCase.getNotesForVolunteer(any(UUID.class), eq(pageable)))
102+
.thenReturn(mockResponse);
103+
104+
// When & Then
105+
mockMvc.perform(get("/api/note/volunteer")
106+
.param("page", "0")
107+
.param("size", "6")
108+
.accept(MediaType.APPLICATION_JSON))
109+
.andExpect(status().isOk())
110+
.andExpect(jsonPath("$.code").value(200))
111+
.andExpect(jsonPath("$.message").value("내 쪽지 조회 성공"))
112+
.andExpect(jsonPath("$.data.content").isArray())
113+
.andExpect(jsonPath("$.data.content[0].id").value(1))
114+
.andExpect(jsonPath("$.data.content[0].title").value("답변 드립니다."))
115+
.andExpect(jsonPath("$.data.content[0].sender_name").value("서울 도서관"))
116+
.andExpect(jsonPath("$.data.content[0].is_read").value(false))
117+
.andExpect(jsonPath("$.data.content[1].id").value(2))
118+
.andExpect(jsonPath("$.data.content[1].title").value("요양원 입니다."))
119+
.andExpect(jsonPath("$.data.content[1].sender_name").value("서울 요양원"))
120+
.andExpect(jsonPath("$.data.content[1].is_read").value(true))
121+
.andExpect(jsonPath("$.data.pageable.pageNumber").value(0))
122+
.andExpect(jsonPath("$.data.pageable.pageSize").value(6))
123+
.andExpect(jsonPath("$.data.totalElements").value(2));
124+
}
77125
}

src/test/java/com/somemore/note/repository/NoteRepositoryImplTest.java

Lines changed: 52 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
package com.somemore.note.repository;
22

33
import com.somemore.IntegrationTestSupport;
4+
import com.somemore.center.domain.Center;
5+
import com.somemore.center.repository.CenterJpaRepository;
46
import com.somemore.note.domain.Note;
57
import com.somemore.note.repository.mapper.NoteReceiverViewForCenter;
8+
import com.somemore.note.repository.mapper.NoteReceiverViewForVolunteer;
69
import com.somemore.volunteer.domain.Volunteer;
710
import com.somemore.volunteer.repository.VolunteerJpaRepository;
8-
import org.junit.jupiter.api.BeforeEach;
911
import org.junit.jupiter.api.DisplayName;
1012
import org.junit.jupiter.api.Test;
1113
import org.springframework.beans.factory.annotation.Autowired;
@@ -28,18 +30,15 @@ class NoteRepositoryImplTest extends IntegrationTestSupport {
2830
@Autowired
2931
private VolunteerJpaRepository volunteerJpaRepository;
3032

31-
private UUID centerId;
32-
33-
@BeforeEach
34-
void setUp() {
35-
centerId = UUID.randomUUID();
36-
createTestNotes(centerId);
37-
}
33+
@Autowired
34+
private CenterJpaRepository centerJpaRepository;
3835

3936
@DisplayName("기관은 자신에게 수신된 쪽지를 페이지로 확인할 수 있다. (Repository)")
4037
@Test
4138
void findNotesByReceiverIsCenter() {
4239
//given
40+
UUID centerId = UUID.randomUUID();
41+
createTestNotesForCenter(centerId);
4342
Pageable pageable = PageRequest.of(1, 6);
4443

4544
//when
@@ -52,7 +51,25 @@ void findNotesByReceiverIsCenter() {
5251
assertThat(result.getContent().getFirst().title()).isEqualTo("Note 9");
5352
}
5453

55-
private void createTestNotes(UUID centerId) {
54+
@DisplayName("봉사자는 자신에게 수신된 쪽지를 페이지로 확인할 수 있다. (Repository)")
55+
@Test
56+
void findNotesByReceiverIsVolunteer() {
57+
//given
58+
UUID volunteerId = UUID.randomUUID();
59+
createTestNotesForVolunteer(volunteerId);
60+
Pageable pageable = PageRequest.of(1, 6);
61+
62+
//when
63+
Page<NoteReceiverViewForVolunteer> result = noteRepository.findNotesByReceiverIsVolunteer(volunteerId, pageable);
64+
65+
//then
66+
assertThat(result).isNotNull();
67+
assertThat(result.getContent()).hasSize(6);
68+
assertThat(result.getTotalElements()).isEqualTo(15);
69+
assertThat(result.getContent().getFirst().title()).isEqualTo("Note 9");
70+
}
71+
72+
private void createTestNotesForCenter(UUID centerId) {
5673
for (int i = 1; i <= 15; i++) {
5774
Volunteer volunteer = createVolunteer();
5875
volunteerJpaRepository.save(volunteer);
@@ -66,4 +83,30 @@ private Volunteer createVolunteer() {
6683
Volunteer volunteer = Volunteer.createDefault(NAVER, UUID.randomUUID().toString());
6784
return volunteerJpaRepository.save(volunteer);
6885
}
86+
87+
private void createTestNotesForVolunteer(UUID volunteerId) {
88+
for (int i = 1; i <= 15; i++) {
89+
Center center = createCenter();
90+
91+
Note note = Note.create(center.getId(), volunteerId, "Note " + i, "내용");
92+
noteRepository.save(note);
93+
}
94+
}
95+
96+
private Center createCenter() {
97+
Center center = Center.create(
98+
"기본 기관 이름",
99+
"010-1234-5678",
100+
"http://example.com/image.jpg",
101+
"기관 소개 내용",
102+
"http://example.com",
103+
"account123",
104+
"password123"
105+
);
106+
107+
centerJpaRepository.save(center);
108+
109+
return center;
110+
}
111+
69112
}

0 commit comments

Comments
 (0)