-
Notifications
You must be signed in to change notification settings - Fork 0
[Feat/#66] 열린피드백 학생 앱 API 추가 #67
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
Merged
Merged
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
432e984
feat: 열린피드백 마이그레이션과 도메인/리포지토리/서비스 기반 추가
xeoxxn 3b8c418
feat: 열린피드백 상세 조회 API 추가
xeoxxn 005d9bb
feat: 열린피드백 목록 조회 API 추가
xeoxxn eeecb6f
feat: 열린피드백 질문 등록 API 추가
xeoxxn f0de0b7
feat: 열린피드백 회차 필터 조회 API 추가
xeoxxn fc8b0b7
fix: 열린피드백 엔드포인트를 다른 app-api와 동일하게 /v1/app 하위로 이동
xeoxxn ee137da
refactor: 실질적 이득 없는 조회 메서드의 readOnly=true 제거
xeoxxn c9a7420
chore: 마이그레이션 버전을 V9에서 V12로 재조정
jjunh33 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
54 changes: 54 additions & 0 deletions
54
api/app-api/src/main/java/kr/ac/kookmin/stream/api/app/welfare/feedback/AppFeedbackApi.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| package kr.ac.kookmin.stream.api.app.welfare.feedback; | ||
|
|
||
| import io.swagger.v3.oas.annotations.Operation; | ||
| import io.swagger.v3.oas.annotations.tags.Tag; | ||
| import kr.ac.kookmin.stream.api.app.AppApiUser; | ||
| import kr.ac.kookmin.stream.api.app.welfare.feedback.request.FeedbackCreateRequest; | ||
| import kr.ac.kookmin.stream.api.app.welfare.feedback.response.FeedbackResponse; | ||
| import kr.ac.kookmin.stream.api.app.welfare.feedback.response.FeedbackRoundsResponse; | ||
| import kr.ac.kookmin.stream.api.common.dto.ApiResponse; | ||
| import kr.ac.kookmin.stream.api.common.dto.PageParams; | ||
| import kr.ac.kookmin.stream.api.common.dto.PageResponse; | ||
| import kr.ac.kookmin.stream.api.common.openapi.ApiErrorCode; | ||
| import kr.ac.kookmin.stream.common.CommonErrorCode; | ||
| import kr.ac.kookmin.stream.welfare.domain.feedback.domain.FeedbackErrorCode; | ||
| import org.springdoc.core.annotations.ParameterObject; | ||
|
|
||
| /** | ||
| * 학생 앱 열린피드백 API의 문서 명세. 구현은 {@link AppFeedbackController}가 맡는다. | ||
| * <p> | ||
| * 스웨거 문서용 어노테이션만 이쪽에 두고 컨트롤러에는 라우팅과 본문만 남긴다. 경로 매핑과 | ||
| * 파라미터 바인딩(@{@code RequestParam}, @{@code PathVariable}, @{@code ModelAttribute} 등)은 구현체에 둔다. | ||
| */ | ||
| @Tag(name = "열린피드백", description = "학생 앱 열린피드백 질문 등록·조회") | ||
| public interface AppFeedbackApi { | ||
|
|
||
| /** 피드백 목록. year/round로 필터링하고 페이지 단위로 조회한다. */ | ||
| @Operation(summary = "피드백 목록 조회", | ||
| description = "연도(year)·회차(round)로 필터링해 열린피드백 목록을 페이지 단위로 조회한다. " | ||
| + "year를 생략하면 전체 연도, round를 생략하면 그 안의 전체 회차를 대상으로 한다.") | ||
| @ApiErrorCode(type = FeedbackErrorCode.class, codes = {"INVALID_FEEDBACK_ROUND"}) | ||
| ApiResponse<PageResponse<FeedbackResponse>> getFeedbacks( | ||
| AppApiUser apiUser, | ||
| Integer year, | ||
| Integer round, | ||
| @ParameterObject PageParams pageParams | ||
| ); | ||
|
|
||
| /** 피드백 상세. */ | ||
| @Operation(summary = "피드백 상세 조회") | ||
| @ApiErrorCode(type = FeedbackErrorCode.class, codes = {"FEEDBACK_NOT_FOUND"}) | ||
| ApiResponse<FeedbackResponse> getFeedback(AppApiUser apiUser, Long feedbackId); | ||
|
|
||
| /** 피드백 질문 등록. 회차는 현재 열려 있는 회차로 서버가 자동 배정한다. */ | ||
| @Operation(summary = "피드백 질문 등록", | ||
| description = "질문을 등록한다. 연도·회차는 현재 접수 기간이 열려 있는 회차로 서버가 자동 배정한다.") | ||
| @ApiErrorCode(type = CommonErrorCode.class, codes = {"INVALID_INPUT"}) | ||
| @ApiErrorCode(type = FeedbackErrorCode.class, codes = {"FEEDBACK_NOT_OPEN"}) | ||
| ApiResponse<FeedbackResponse> createFeedback(AppApiUser apiUser, FeedbackCreateRequest request); | ||
|
|
||
| /** 목록 화면의 연도 드롭다운·회차 칩을 그리기 위한 필터 옵션. */ | ||
| @Operation(summary = "피드백 회차 필터 조회", | ||
| description = "year를 생략하면 현재 연도 기준으로, 회차가 하나라도 존재했던 전체 연도 목록과 그 연도에 실제로 존재하는 회차 목록을 함께 내려준다.") | ||
| ApiResponse<FeedbackRoundsResponse> getFeedbackRounds(AppApiUser apiUser, Integer year); | ||
| } |
70 changes: 70 additions & 0 deletions
70
...pi/src/main/java/kr/ac/kookmin/stream/api/app/welfare/feedback/AppFeedbackController.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,70 @@ | ||
| package kr.ac.kookmin.stream.api.app.welfare.feedback; | ||
|
|
||
| import jakarta.validation.Valid; | ||
| import kr.ac.kookmin.stream.api.app.AppApiUser; | ||
| import kr.ac.kookmin.stream.api.app.welfare.feedback.request.FeedbackCreateRequest; | ||
| import kr.ac.kookmin.stream.api.app.welfare.feedback.response.FeedbackResponse; | ||
| import kr.ac.kookmin.stream.api.app.welfare.feedback.response.FeedbackRoundsResponse; | ||
| import kr.ac.kookmin.stream.api.common.dto.ApiResponse; | ||
| import kr.ac.kookmin.stream.api.common.dto.PageParams; | ||
| import kr.ac.kookmin.stream.api.common.dto.PageResponse; | ||
| import kr.ac.kookmin.stream.common.PageResult; | ||
| import kr.ac.kookmin.stream.welfare.domain.feedback.domain.FeedbackRoundOptions; | ||
| import kr.ac.kookmin.stream.welfare.domain.feedback.domain.OpenFeedback; | ||
| import kr.ac.kookmin.stream.welfare.domain.feedback.service.OpenFeedbackService; | ||
| import lombok.RequiredArgsConstructor; | ||
| import org.springframework.web.bind.annotation.GetMapping; | ||
| import org.springframework.web.bind.annotation.ModelAttribute; | ||
| import org.springframework.web.bind.annotation.PathVariable; | ||
| import org.springframework.web.bind.annotation.PostMapping; | ||
| import org.springframework.web.bind.annotation.RequestBody; | ||
| import org.springframework.web.bind.annotation.RequestMapping; | ||
| import org.springframework.web.bind.annotation.RequestParam; | ||
| import org.springframework.web.bind.annotation.RestController; | ||
|
|
||
| @RestController | ||
| @RequestMapping("/v1/app/feedbacks") | ||
| @RequiredArgsConstructor | ||
| public class AppFeedbackController implements AppFeedbackApi { | ||
|
|
||
| private final OpenFeedbackService openFeedbackService; | ||
|
|
||
| @Override | ||
| @GetMapping("/{feedbackId}") | ||
| public ApiResponse<FeedbackResponse> getFeedback(AppApiUser apiUser, @PathVariable Long feedbackId) { | ||
| OpenFeedback feedback = openFeedbackService.getById(feedbackId); | ||
| return ApiResponse.success(FeedbackResponse.from(feedback)); | ||
| } | ||
|
|
||
| @Override | ||
| @GetMapping | ||
| public ApiResponse<PageResponse<FeedbackResponse>> getFeedbacks( | ||
| AppApiUser apiUser, | ||
| @RequestParam(required = false) Integer year, | ||
| @RequestParam(required = false) Integer round, | ||
| @Valid @ModelAttribute PageParams pageParams | ||
| ) { | ||
| PageResult<OpenFeedback> result = openFeedbackService.search(year, round, pageParams.toOffset()); | ||
| return ApiResponse.success(PageResponse.from(result, FeedbackResponse::from)); | ||
| } | ||
|
|
||
| @Override | ||
| @PostMapping | ||
| public ApiResponse<FeedbackResponse> createFeedback( | ||
| AppApiUser apiUser, | ||
| @Valid @RequestBody FeedbackCreateRequest request | ||
| ) { | ||
| OpenFeedback feedback = openFeedbackService.create(apiUser.userId(), request.question()); | ||
| return ApiResponse.success(FeedbackResponse.from(feedback)); | ||
| } | ||
|
|
||
| @Override | ||
| @GetMapping("/rounds") | ||
| public ApiResponse<FeedbackRoundsResponse> getFeedbackRounds( | ||
| AppApiUser apiUser, | ||
| @RequestParam(required = false) Integer year | ||
| ) { | ||
| FeedbackRoundOptions options = openFeedbackService.getRoundOptions(year); | ||
| return ApiResponse.success(FeedbackRoundsResponse.from(options)); | ||
| } | ||
| } |
12 changes: 12 additions & 0 deletions
12
...ain/java/kr/ac/kookmin/stream/api/app/welfare/feedback/request/FeedbackCreateRequest.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| package kr.ac.kookmin.stream.api.app.welfare.feedback.request; | ||
|
|
||
| import jakarta.validation.constraints.NotBlank; | ||
| import jakarta.validation.constraints.Size; | ||
|
|
||
| public record FeedbackCreateRequest( | ||
|
|
||
| @NotBlank(message = "피드백 내용을 입력해 주세요.") | ||
| @Size(max = 500, message = "피드백 내용은 500자 이하로 입력해 주세요.") | ||
| String question | ||
| ) { | ||
| } |
26 changes: 26 additions & 0 deletions
26
...rc/main/java/kr/ac/kookmin/stream/api/app/welfare/feedback/response/FeedbackResponse.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| package kr.ac.kookmin.stream.api.app.welfare.feedback.response; | ||
|
|
||
| import java.time.LocalDateTime; | ||
| import kr.ac.kookmin.stream.welfare.domain.feedback.domain.OpenFeedback; | ||
|
|
||
| public record FeedbackResponse( | ||
| Long feedbackId, | ||
| int year, | ||
| int round, | ||
| String question, | ||
| LocalDateTime questionedAt, | ||
| LocalDateTime answeredAt, | ||
| String answer | ||
| ) { | ||
| public static FeedbackResponse from(OpenFeedback feedback) { | ||
| return new FeedbackResponse( | ||
| feedback.id(), | ||
| feedback.year(), | ||
| feedback.round(), | ||
| feedback.question(), | ||
| feedback.questionedAt(), | ||
| feedback.answeredAt(), | ||
| feedback.answer() | ||
| ); | ||
| } | ||
| } |
11 changes: 11 additions & 0 deletions
11
...n/java/kr/ac/kookmin/stream/api/app/welfare/feedback/response/FeedbackRoundsResponse.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| package kr.ac.kookmin.stream.api.app.welfare.feedback.response; | ||
|
|
||
| import java.util.List; | ||
| import kr.ac.kookmin.stream.welfare.domain.feedback.domain.FeedbackRoundOptions; | ||
|
|
||
| public record FeedbackRoundsResponse(List<Integer> years, int year, List<Integer> rounds) { | ||
|
|
||
| public static FeedbackRoundsResponse from(FeedbackRoundOptions options) { | ||
| return new FeedbackRoundsResponse(options.years(), options.year(), options.rounds()); | ||
| } | ||
| } |
20 changes: 20 additions & 0 deletions
20
.../src/main/java/kr/ac/kookmin/stream/welfare/domain/feedback/domain/FeedbackErrorCode.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| package kr.ac.kookmin.stream.welfare.domain.feedback.domain; | ||
|
|
||
| import kr.ac.kookmin.stream.common.ErrorCode; | ||
| import kr.ac.kookmin.stream.common.ErrorStatus; | ||
| import lombok.AllArgsConstructor; | ||
| import lombok.Getter; | ||
| import lombok.experimental.Accessors; | ||
|
|
||
| @Getter | ||
| @Accessors(fluent = true) | ||
| @AllArgsConstructor | ||
| public enum FeedbackErrorCode implements ErrorCode { | ||
|
|
||
| INVALID_FEEDBACK_ROUND(ErrorStatus.BAD_REQUEST, "유효하지 않은 열린피드백 회차입니다."), | ||
| FEEDBACK_NOT_FOUND(ErrorStatus.NOT_FOUND, "존재하지 않는 피드백입니다."), | ||
| FEEDBACK_NOT_OPEN(ErrorStatus.CONFLICT, "현재 열린피드백 질문 접수 기간이 아닙니다."); | ||
|
|
||
| private final int status; | ||
| private final String message; | ||
| } |
11 changes: 11 additions & 0 deletions
11
...fare/src/main/java/kr/ac/kookmin/stream/welfare/domain/feedback/domain/FeedbackRound.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| package kr.ac.kookmin.stream.welfare.domain.feedback.domain; | ||
|
|
||
| import java.time.LocalDateTime; | ||
|
|
||
| // 관리자가 여는 열린피드백 접수 회차. 오픈/마감 시각과 함께 연도별로 관리한다(연도별로 1차부터 다시 시작). | ||
| public record FeedbackRound(Long id, int year, int round, LocalDateTime opensAt, LocalDateTime closesAt) { | ||
|
|
||
| public static FeedbackRound of(Long id, int year, int round, LocalDateTime opensAt, LocalDateTime closesAt) { | ||
| return new FeedbackRound(id, year, round, opensAt, closesAt); | ||
| } | ||
| } |
12 changes: 12 additions & 0 deletions
12
...c/main/java/kr/ac/kookmin/stream/welfare/domain/feedback/domain/FeedbackRoundOptions.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| package kr.ac.kookmin.stream.welfare.domain.feedback.domain; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| // 목록 화면의 연도 드롭다운·회차 칩을 그리는 데 쓰는 조회 전용 값 객체. | ||
| // years: 피드백 회차가 하나라도 존재했던 전체 연도. rounds: year 기준으로 실제 존재하는 회차 번호. | ||
| public record FeedbackRoundOptions(List<Integer> years, int year, List<Integer> rounds) { | ||
|
|
||
| public static FeedbackRoundOptions of(List<Integer> years, int year, List<Integer> rounds) { | ||
| return new FeedbackRoundOptions(years, year, rounds); | ||
| } | ||
| } |
37 changes: 19 additions & 18 deletions
37
...lfare/src/main/java/kr/ac/kookmin/stream/welfare/domain/feedback/domain/OpenFeedback.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,35 +1,36 @@ | ||
| package kr.ac.kookmin.stream.welfare.domain.feedback.domain; | ||
|
|
||
| import java.time.LocalDateTime; | ||
| import lombok.AccessLevel; | ||
| import lombok.AllArgsConstructor; | ||
| import lombok.EqualsAndHashCode; | ||
| import lombok.Getter; | ||
|
|
||
| @Getter | ||
| @EqualsAndHashCode | ||
| @AllArgsConstructor(access = AccessLevel.PRIVATE) | ||
| public class OpenFeedback { | ||
| public record OpenFeedback( | ||
| Long id, | ||
| int year, | ||
| int round, | ||
| String question, | ||
| LocalDateTime questionedAt, | ||
| String answer, | ||
| LocalDateTime answeredAt, | ||
| Long createdBy, | ||
| Long answeredBy | ||
| ) { | ||
|
|
||
| private Long id; | ||
| private int round; | ||
| private String category; | ||
| private String question; | ||
| private String answer; | ||
| private LocalDateTime answeredAt; | ||
| private Long createdBy; | ||
| private Long answeredBy; | ||
| // 회차는 서버가 자동 배정하므로 여기서 받는다(요청 시각 = questionedAt, 아직 답변 없음). | ||
| public static OpenFeedback create(int year, int round, String question, Long createdBy) { | ||
| return new OpenFeedback(null, year, round, question, LocalDateTime.now(), null, null, createdBy, null); | ||
| } | ||
|
|
||
| // DB에서 복원할 때 모든 필드를 그대로 받는다. | ||
| public static OpenFeedback of( | ||
| Long id, | ||
| int year, | ||
| int round, | ||
| String category, | ||
| String question, | ||
| LocalDateTime questionedAt, | ||
| String answer, | ||
| LocalDateTime answeredAt, | ||
| Long createdBy, | ||
| Long answeredBy | ||
| ) { | ||
| return new OpenFeedback(id, round, category, question, answer, answeredAt, createdBy, answeredBy); | ||
| return new OpenFeedback(id, year, round, question, questionedAt, answer, answeredAt, createdBy, answeredBy); | ||
| } | ||
| } |
18 changes: 18 additions & 0 deletions
18
...java/kr/ac/kookmin/stream/welfare/domain/feedback/repository/FeedbackRoundRepository.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| package kr.ac.kookmin.stream.welfare.domain.feedback.repository; | ||
|
|
||
| import java.time.LocalDateTime; | ||
| import java.util.List; | ||
| import java.util.Optional; | ||
| import kr.ac.kookmin.stream.welfare.domain.feedback.domain.FeedbackRound; | ||
|
|
||
| public interface FeedbackRoundRepository { | ||
|
|
||
| // now 시각 기준으로 접수 기간(opens_at~closes_at) 안에 있는 회차 하나를 찾는다. 여러 회차 기간이 안 겹친다는 전제. | ||
| Optional<FeedbackRound> findOpenAt(LocalDateTime now); | ||
|
|
||
| // 회차가 하나라도 존재했던 연도 목록(최신순) — 목록 화면 연도 드롭다운용 | ||
| List<Integer> findDistinctYears(); | ||
|
|
||
| // 해당 연도에 실제로 존재하는 회차 번호(오름차순) — 목록 화면 회차 칩용 | ||
| List<Integer> findRoundsByYear(int year); | ||
| } |
16 changes: 16 additions & 0 deletions
16
.../java/kr/ac/kookmin/stream/welfare/domain/feedback/repository/OpenFeedbackRepository.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| package kr.ac.kookmin.stream.welfare.domain.feedback.repository; | ||
|
|
||
| import java.util.Optional; | ||
| import kr.ac.kookmin.stream.common.PageOffset; | ||
| import kr.ac.kookmin.stream.common.PageResult; | ||
| import kr.ac.kookmin.stream.welfare.domain.feedback.domain.OpenFeedback; | ||
|
|
||
| public interface OpenFeedbackRepository { | ||
|
|
||
| Optional<OpenFeedback> findById(Long id); | ||
|
|
||
| // year/round가 null이면 그 조건은 필터하지 않는다 | ||
| PageResult<OpenFeedback> search(Integer year, Integer round, PageOffset pageOffset); | ||
|
|
||
| OpenFeedback save(OpenFeedback feedback); | ||
| } |
20 changes: 20 additions & 0 deletions
20
...c/main/java/kr/ac/kookmin/stream/welfare/domain/feedback/service/OpenFeedbackService.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| package kr.ac.kookmin.stream.welfare.domain.feedback.service; | ||
|
|
||
| import kr.ac.kookmin.stream.common.PageOffset; | ||
| import kr.ac.kookmin.stream.common.PageResult; | ||
| import kr.ac.kookmin.stream.welfare.domain.feedback.domain.FeedbackRoundOptions; | ||
| import kr.ac.kookmin.stream.welfare.domain.feedback.domain.OpenFeedback; | ||
|
|
||
| public interface OpenFeedbackService { | ||
|
|
||
| OpenFeedback getById(Long id); | ||
|
|
||
| // year/round가 null이면 그 조건은 전체(필터 없음) | ||
| PageResult<OpenFeedback> search(Integer year, Integer round, PageOffset pageOffset); | ||
|
|
||
| // 회차는 현재 열려 있는 회차로 서버가 자동 배정한다 | ||
| OpenFeedback create(Long memberId, String question); | ||
|
|
||
| // year가 null이면 현재 연도 기준 | ||
| FeedbackRoundOptions getRoundOptions(Integer year); | ||
| } |
58 changes: 58 additions & 0 deletions
58
...va/kr/ac/kookmin/stream/welfare/domain/feedback/service/impl/OpenFeedbackServiceImpl.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,58 @@ | ||
| package kr.ac.kookmin.stream.welfare.domain.feedback.service.impl; | ||
|
|
||
| import java.time.LocalDateTime; | ||
| import java.util.List; | ||
| import kr.ac.kookmin.stream.common.BusinessException; | ||
| import kr.ac.kookmin.stream.common.PageOffset; | ||
| import kr.ac.kookmin.stream.common.PageResult; | ||
| import kr.ac.kookmin.stream.welfare.domain.feedback.domain.FeedbackErrorCode; | ||
| import kr.ac.kookmin.stream.welfare.domain.feedback.domain.FeedbackRound; | ||
| import kr.ac.kookmin.stream.welfare.domain.feedback.domain.FeedbackRoundOptions; | ||
| import kr.ac.kookmin.stream.welfare.domain.feedback.domain.OpenFeedback; | ||
| import kr.ac.kookmin.stream.welfare.domain.feedback.repository.FeedbackRoundRepository; | ||
| import kr.ac.kookmin.stream.welfare.domain.feedback.repository.OpenFeedbackRepository; | ||
| import kr.ac.kookmin.stream.welfare.domain.feedback.service.OpenFeedbackService; | ||
| import lombok.RequiredArgsConstructor; | ||
| import org.springframework.stereotype.Service; | ||
| import org.springframework.transaction.annotation.Transactional; | ||
|
|
||
| @Service | ||
| @RequiredArgsConstructor | ||
| class OpenFeedbackServiceImpl implements OpenFeedbackService { | ||
|
|
||
| private final OpenFeedbackRepository openFeedbackRepository; | ||
| private final FeedbackRoundRepository feedbackRoundRepository; | ||
|
|
||
| @Override | ||
| public OpenFeedback getById(Long id) { | ||
| return openFeedbackRepository.findById(id) | ||
| .orElseThrow(() -> new BusinessException(FeedbackErrorCode.FEEDBACK_NOT_FOUND)); | ||
| } | ||
|
|
||
| @Override | ||
| public PageResult<OpenFeedback> search(Integer year, Integer round, PageOffset pageOffset) { | ||
| if (round != null && round <= 0) { | ||
| throw new BusinessException(FeedbackErrorCode.INVALID_FEEDBACK_ROUND); | ||
| } | ||
| return openFeedbackRepository.search(year, round, pageOffset); | ||
| } | ||
|
|
||
| @Override | ||
| @Transactional | ||
| public OpenFeedback create(Long memberId, String question) { | ||
| FeedbackRound openRound = feedbackRoundRepository.findOpenAt(LocalDateTime.now()) | ||
| .orElseThrow(() -> new BusinessException(FeedbackErrorCode.FEEDBACK_NOT_OPEN)); | ||
|
|
||
| OpenFeedback feedback = OpenFeedback.create(openRound.year(), openRound.round(), question, memberId); | ||
| return openFeedbackRepository.save(feedback); | ||
| } | ||
|
|
||
| @Override | ||
| public FeedbackRoundOptions getRoundOptions(Integer year) { | ||
| List<Integer> years = feedbackRoundRepository.findDistinctYears(); | ||
| int targetYear = year != null ? year : LocalDateTime.now().getYear(); | ||
| List<Integer> rounds = feedbackRoundRepository.findRoundsByYear(targetYear); | ||
|
|
||
| return FeedbackRoundOptions.of(years, targetYear, rounds); | ||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
조회 전용 Service 메서드에 읽기 전용 트랜잭션 경계를 추가하세요.
OpenFeedbackServiceImpl.getById,search,getRoundOptions는 조회 전용 메서드입니다. 클래스와 인터페이스에도 트랜잭션 선언이 없으므로 세 메서드가 Service 수준의@Transactional(readOnly = true)요구를 위반합니다. 이는 데이터 무결성 문제가 아니라 트랜잭션 경계 규칙 위반입니다.제안 수정
🧰 Tools
🪛 ast-grep (0.45.3)
[warning] 36-36: Avoid LDAP injections
Context: openFeedbackRepository.search(year, round, pageOffset)
Note: [CWE-90] Improper Neutralization of Special Elements used in an LDAP Query ('LDAP Injection'). Security best practice.
(ldap-injection-java)
🤖 Prompt for AI Agents