Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ public enum ExceptionMessage {
UNAUTHORIZED_NOTIFICATION("해당 알림에 권한이 없습니다."),
VOLUNTEER_APPLY_LIST_MISMATCH("봉사 지원 목록과 요청된 봉사 지원 목록이 일치하지 않습니다."),
RECRUIT_BOARD_ID_MISMATCH("모든 봉사 신청이 동일한 모집글 ID를 가져야 합니다."),
NOT_EXISTS_NOTE("존재하지 않는 쪽지입니다.")

;
private final String message;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.somemore.global.exception;

public class NoSuchElementException extends RuntimeException{
public NoSuchElementException(final ExceptionMessage message) {
super(message.getMessage());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.somemore.global.exception.BadRequestException;
import com.somemore.global.exception.DuplicateException;
import com.somemore.global.exception.ImageUploadException;
import com.somemore.global.exception.NoSuchElementException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ProblemDetail;
import org.springframework.web.bind.MethodArgumentNotValidException;
Expand Down Expand Up @@ -56,4 +57,13 @@ ProblemDetail handleMethodArgumentNotValid(final MethodArgumentNotValidException
return problemDetail;
}

@ExceptionHandler(NoSuchElementException.class)
ProblemDetail handleNoSuchElementException(final NoSuchElementException e) {

ProblemDetail problemDetail = ProblemDetail.forStatusAndDetail(HttpStatus.BAD_REQUEST, e.getMessage());
problemDetail.setTitle("데이터가 존재하지 않음");

return problemDetail;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import com.somemore.auth.annotation.CurrentUser;
import com.somemore.global.common.response.ApiResponse;
import com.somemore.note.repository.mapper.NoteDetailViewForCenter;
import com.somemore.note.repository.mapper.NoteDetailViewForVolunteer;
import com.somemore.note.repository.mapper.NoteReceiverViewForCenter;
import com.somemore.note.repository.mapper.NoteReceiverViewForVolunteer;
import com.somemore.note.usecase.NoteQueryUseCase;
Expand Down Expand Up @@ -43,4 +45,24 @@ public ApiResponse<Page<NoteReceiverViewForVolunteer>> getNotesByVolunteerId(@Cu
return ApiResponse.ok(200, response, "내 쪽지 조회 성공");
}

@Secured("ROLE_CENTER")
@Operation(summary = "기관의 자신에게 온 쪽지 상세 조회")
@GetMapping("/center/{noteId}")
public ApiResponse<NoteDetailViewForCenter> getNoteDetailForCenter(@PathVariable Long noteId) {

NoteDetailViewForCenter response = noteQueryUseCase.getNoteDetailForCenter(noteId);

return ApiResponse.ok(200, response, "쪽지 상세 조회 성공");
}

@Secured("ROLE_VOLUNTEER")
@Operation(summary = "봉사자의 자신에게 온 쪽지 상세 조회")
@GetMapping("/volunteer/{noteId}")
public ApiResponse<NoteDetailViewForVolunteer> getNoteDetailForVolunteer(@PathVariable Long noteId) {

NoteDetailViewForVolunteer response = noteQueryUseCase.getNoteDetailForVolunteer(noteId);

return ApiResponse.ok(200, response, "쪽지 상세 조회 성공");
}

}
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
package com.somemore.note.repository;

import com.somemore.note.domain.Note;
import com.somemore.note.repository.mapper.NoteDetailViewForCenter;
import com.somemore.note.repository.mapper.NoteDetailViewForVolunteer;
import com.somemore.note.repository.mapper.NoteReceiverViewForCenter;
import com.somemore.note.repository.mapper.NoteReceiverViewForVolunteer;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

import java.util.Optional;
import java.util.UUID;

public interface NoteRepository {
Note save(Note note);
Page<NoteReceiverViewForCenter> findNotesByReceiverIsCenter(UUID centerId, Pageable pageable);
Page<NoteReceiverViewForVolunteer> findNotesByReceiverIsVolunteer(UUID volunteerId, Pageable pageable);
Optional<NoteDetailViewForCenter> findNoteDetailViewReceiverIsCenter(Long noteId);
Optional<NoteDetailViewForVolunteer> findNoteDetailViewReceiverIsVolunteer(Long noteId);
}
86 changes: 76 additions & 10 deletions src/main/java/com/somemore/note/repository/NoteRepositoryImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import com.somemore.center.domain.QCenter;
import com.somemore.note.domain.Note;
import com.somemore.note.domain.QNote;
import com.somemore.note.repository.mapper.NoteDetailViewForCenter;
import com.somemore.note.repository.mapper.NoteDetailViewForVolunteer;
import com.somemore.note.repository.mapper.NoteReceiverViewForCenter;
import com.somemore.note.repository.mapper.NoteReceiverViewForVolunteer;
import com.somemore.volunteer.domain.QVolunteer;
Expand All @@ -17,6 +19,7 @@
import org.springframework.stereotype.Repository;

import java.util.List;
import java.util.Optional;
import java.util.UUID;

@RequiredArgsConstructor
Expand All @@ -30,6 +33,10 @@ public class NoteRepositoryImpl implements NoteRepository {
private static final QVolunteer volunteer = QVolunteer.volunteer;
private static final QCenter center = QCenter.center;

private static final String SENDER_ID = "senderId";
private static final String SENDER_NAME = "senderName";
private static final String SENDER_PROFILE_IMG_LINK = "senderProfileImgLink";

@Override
public Note save(Note note) {
return noteJpaRepository.save(note);
Expand All @@ -38,17 +45,16 @@ public Note save(Note note) {
@Override
public Page<NoteReceiverViewForCenter> findNotesByReceiverIsCenter(UUID centerId, Pageable pageable) {

BooleanExpression activeVolunteer = volunteer.deleted.eq(false);
BooleanExpression condition = note.receiverId.eq(centerId)
.and(note.deleted.eq(false));
BooleanExpression activeVolunteer = isActiveVolunteer();
BooleanExpression condition = isReceiver(centerId);

List<NoteReceiverViewForCenter> results = queryFactory
.select(Projections.constructor(
NoteReceiverViewForCenter.class,
note.id,
note.title,
volunteer.id.as("senderId"),
volunteer.nickname.as("senderName"),
volunteer.id.as(SENDER_ID),
volunteer.nickname.as(SENDER_NAME),
note.isRead
))
.from(note)
Expand All @@ -69,17 +75,16 @@ public Page<NoteReceiverViewForCenter> findNotesByReceiverIsCenter(UUID centerId

@Override
public Page<NoteReceiverViewForVolunteer> findNotesByReceiverIsVolunteer(UUID volunteerId, Pageable pageable) {
BooleanExpression activeCenter = center.deleted.eq(false);
BooleanExpression condition = note.receiverId.eq(volunteerId)
.and(note.deleted.eq(false));
BooleanExpression activeCenter = isActiveCenter();
BooleanExpression condition = isReceiver(volunteerId);

List<NoteReceiverViewForVolunteer> results = queryFactory
.select(Projections.constructor(
NoteReceiverViewForVolunteer.class,
note.id,
note.title,
center.id.as("senderId"),
center.name.as("senderName"),
center.id.as(SENDER_ID),
center.name.as(SENDER_NAME),
note.isRead
))
.from(note)
Expand All @@ -98,4 +103,65 @@ public Page<NoteReceiverViewForVolunteer> findNotesByReceiverIsVolunteer(UUID vo
return PageableExecutionUtils.getPage(results, pageable, count::fetchOne);
}

@Override
public Optional<NoteDetailViewForCenter> findNoteDetailViewReceiverIsCenter(Long noteId) {

BooleanExpression activeVolunteer = isActiveVolunteer();

NoteDetailViewForCenter result = queryFactory
.select(Projections.constructor(
NoteDetailViewForCenter.class,
note.id,
note.title,
note.content,
volunteer.id.as(SENDER_ID),
volunteer.nickname.as(SENDER_NAME),
volunteer.imgUrl.as(SENDER_PROFILE_IMG_LINK),
note.createdAt
))
.from(note)
.join(volunteer).on(note.senderId.eq(volunteer.id).and(activeVolunteer))
.where(note.id.eq(noteId).and(note.deleted.eq(false)))
.fetchOne();

return Optional.ofNullable(result);
}

@Override
public Optional<NoteDetailViewForVolunteer> findNoteDetailViewReceiverIsVolunteer(Long noteId) {

BooleanExpression activeCenter = isActiveCenter();

NoteDetailViewForVolunteer result = queryFactory
.select(Projections.constructor(
NoteDetailViewForVolunteer.class,
note.id,
note.title,
note.content,
center.id.as(SENDER_ID),
center.name.as(SENDER_NAME),
center.imgUrl.as(SENDER_PROFILE_IMG_LINK),
note.createdAt
))
.from(note)
.join(center).on(note.senderId.eq(center.id).and(activeCenter))
.where(note.id.eq(noteId).and(note.deleted.eq(false)))
.fetchOne();

return Optional.ofNullable(result);
}

private static BooleanExpression isReceiver(UUID receiverId) {
return note.receiverId.eq(receiverId)
.and(note.deleted.eq(false));
}

private BooleanExpression isActiveVolunteer() {
return volunteer.deleted.eq(false);
}

private static BooleanExpression isActiveCenter() {
return center.deleted.eq(false);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.somemore.note.repository.mapper;

import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.fasterxml.jackson.databind.annotation.JsonNaming;

import java.time.LocalDateTime;
import java.util.UUID;

@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
public record NoteDetailViewForCenter(
Long noteId,
String title,
String content,
UUID senderId,
String senderName,
String senderProfileImgLink,
LocalDateTime createdAt
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.somemore.note.repository.mapper;

import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.fasterxml.jackson.databind.annotation.JsonNaming;

import java.time.LocalDateTime;
import java.util.UUID;

@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
public record NoteDetailViewForVolunteer(
Long noteId,
String title,
String content,
UUID senderId,
String senderName,
String senderProfileImgLink,
LocalDateTime createdAt
) {
}
18 changes: 18 additions & 0 deletions src/main/java/com/somemore/note/service/NoteQueryService.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package com.somemore.note.service;

import com.somemore.global.exception.NoSuchElementException;
import com.somemore.note.repository.NoteRepository;
import com.somemore.note.repository.mapper.NoteDetailViewForCenter;
import com.somemore.note.repository.mapper.NoteDetailViewForVolunteer;
import com.somemore.note.repository.mapper.NoteReceiverViewForCenter;
import com.somemore.note.repository.mapper.NoteReceiverViewForVolunteer;
import com.somemore.note.usecase.NoteQueryUseCase;
Expand All @@ -12,6 +15,8 @@

import java.util.UUID;

import static com.somemore.global.exception.ExceptionMessage.NOT_EXISTS_NOTE;

@RequiredArgsConstructor
@Service
@Transactional(readOnly = true)
Expand All @@ -28,4 +33,17 @@ public Page<NoteReceiverViewForCenter> getNotesForCenter(UUID centerId, Pageable
public Page<NoteReceiverViewForVolunteer> getNotesForVolunteer(UUID volunteerId, Pageable pageable) {
return noteRepository.findNotesByReceiverIsVolunteer(volunteerId, pageable);
}

@Override
public NoteDetailViewForCenter getNoteDetailForCenter(Long noteId) {
return noteRepository.findNoteDetailViewReceiverIsCenter(noteId)
.orElseThrow(() -> new NoSuchElementException(NOT_EXISTS_NOTE));
}

@Override
public NoteDetailViewForVolunteer getNoteDetailForVolunteer(Long noteId) {
return noteRepository.findNoteDetailViewReceiverIsVolunteer(noteId)
.orElseThrow(() -> new NoSuchElementException(NOT_EXISTS_NOTE));
}

}
4 changes: 4 additions & 0 deletions src/main/java/com/somemore/note/usecase/NoteQueryUseCase.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.somemore.note.usecase;

import com.somemore.note.repository.mapper.NoteDetailViewForCenter;
import com.somemore.note.repository.mapper.NoteDetailViewForVolunteer;
import com.somemore.note.repository.mapper.NoteReceiverViewForCenter;
import com.somemore.note.repository.mapper.NoteReceiverViewForVolunteer;
import org.springframework.data.domain.Page;
Expand All @@ -10,4 +12,6 @@
public interface NoteQueryUseCase {
Page<NoteReceiverViewForCenter> getNotesForCenter(UUID centerId, Pageable pageable);
Page<NoteReceiverViewForVolunteer> getNotesForVolunteer(UUID volunteerId, Pageable pageable);
NoteDetailViewForCenter getNoteDetailForCenter(Long noteId);
NoteDetailViewForVolunteer getNoteDetailForVolunteer(Long noteId);
}
Loading
Loading