diff --git a/src/main/generated/com/chwipoClova/interview/entity/QInterview.java b/src/main/generated/com/chwipoClova/interview/entity/QInterview.java index dfdb300..ca2baa3 100644 --- a/src/main/generated/com/chwipoClova/interview/entity/QInterview.java +++ b/src/main/generated/com/chwipoClova/interview/entity/QInterview.java @@ -22,6 +22,8 @@ public class QInterview extends EntityPathBase { public static final QInterview interview = new QInterview("interview"); + public final StringPath feedback = createString("feedback"); + public final NumberPath interviewId = createNumber("interviewId", Long.class); public final StringPath recruitSummary = createString("recruitSummary"); @@ -30,6 +32,8 @@ public class QInterview extends EntityPathBase { public final StringPath resumeSummary = createString("resumeSummary"); + public final NumberPath status = createNumber("status", Integer.class); + public final StringPath title = createString("title"); public final com.chwipoClova.user.entity.QUser user; diff --git a/src/main/java/com/chwipoClova/common/exception/ExceptionCode.java b/src/main/java/com/chwipoClova/common/exception/ExceptionCode.java index 536119f..4e5ebda 100644 --- a/src/main/java/com/chwipoClova/common/exception/ExceptionCode.java +++ b/src/main/java/com/chwipoClova/common/exception/ExceptionCode.java @@ -39,6 +39,10 @@ public enum ExceptionCode { INTERVIEW_LIST_OVER("881", "면접 최대 개수를 초과하였습니다."), + INTERVIEW_COMPLETE("882", "완료 된 면접 입니다."), + + INTERVIEW_NOT_COMPLETE("883", "미완료 된 면접 입니다."), + QA_NULL("890", "질문 정보가 올바르지 않습니다."), TOKEN_NULL("950", "토큰정보가 올바르지 않습니다.") diff --git a/src/main/java/com/chwipoClova/feedback/controller/FeedbackController.java b/src/main/java/com/chwipoClova/feedback/controller/FeedbackController.java index e037cda..52df302 100644 --- a/src/main/java/com/chwipoClova/feedback/controller/FeedbackController.java +++ b/src/main/java/com/chwipoClova/feedback/controller/FeedbackController.java @@ -26,15 +26,7 @@ public class FeedbackController { private final FeedbackService feedbackService; - @Operation(summary = "피드백 재생성", description = "피드백 재생성") - @PostMapping("/generateFeedback") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = String.class))) - } - ) - public CommonResponse generateFeedback (@RequestBody FeedbackGenerateReq feedbackGenerateReq) throws Exception { - return feedbackService.generateFeedback(feedbackGenerateReq); - } + } diff --git a/src/main/java/com/chwipoClova/feedback/service/FeedbackService.java b/src/main/java/com/chwipoClova/feedback/service/FeedbackService.java index 5daf0c1..fc48398 100644 --- a/src/main/java/com/chwipoClova/feedback/service/FeedbackService.java +++ b/src/main/java/com/chwipoClova/feedback/service/FeedbackService.java @@ -91,7 +91,12 @@ public CommonResponse generateFeedback(FeedbackGenerateReq feedbackGenerateReq) Long userId = feedbackGenerateReq.getUserId(); userRepository.findById(userId).orElseThrow(() -> new CommonException(ExceptionCode.USER_NULL.getMessage(), ExceptionCode.USER_NULL.getCode())); - interviewRepository.findByUserUserIdAndInterviewId(userId, interviewId).orElseThrow(() -> new CommonException(ExceptionCode.INTERVIEW_NULL.getMessage(), ExceptionCode.INTERVIEW_NULL.getCode())); + Interview interview = interviewRepository.findByUserUserIdAndInterviewId(userId, interviewId).orElseThrow(() -> new CommonException(ExceptionCode.INTERVIEW_NULL.getMessage(), ExceptionCode.INTERVIEW_NULL.getCode())); + Integer status = interview.getStatus(); + + if (status != 1) { + throw new CommonException(ExceptionCode.INTERVIEW_NOT_COMPLETE.getMessage(), ExceptionCode.INTERVIEW_NOT_COMPLETE.getCode()); + } List qaList = qaRepository.findByInterviewInterviewIdOrderByQaId(interviewId); diff --git a/src/main/java/com/chwipoClova/interview/controller/InterviewController.java b/src/main/java/com/chwipoClova/interview/controller/InterviewController.java index e0da8b1..ea5bf7b 100644 --- a/src/main/java/com/chwipoClova/interview/controller/InterviewController.java +++ b/src/main/java/com/chwipoClova/interview/controller/InterviewController.java @@ -1,22 +1,31 @@ package com.chwipoClova.interview.controller; +import com.chwipoClova.common.response.CommonResponse; +import com.chwipoClova.feedback.request.FeedbackGenerateReq; +import com.chwipoClova.interview.request.InterviewFeedbackGenerateReq; +import com.chwipoClova.interview.request.InterviewInitQaReq; import com.chwipoClova.interview.request.InterviewInsertReq; +import com.chwipoClova.interview.request.InterviewQaAnswerInsertReq; import com.chwipoClova.interview.response.InterviewInsertRes; import com.chwipoClova.interview.response.InterviewListRes; -import com.chwipoClova.interview.response.InterviewNotCompRes; +import com.chwipoClova.interview.response.InterviewQaListRes; import com.chwipoClova.interview.response.InterviewRes; import com.chwipoClova.interview.service.InterviewService; +import com.chwipoClova.qa.request.QaAnswerInsertReq; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; +import java.io.IOException; import java.util.List; @Slf4j @@ -64,18 +73,59 @@ public List getInterviewList(@Schema(description = "userId", e return interviewService.selectInterviewList(userId); } - @Operation(summary = "미완료 면접 질문 조회", description = "미완료 면접 질문 조회") - @GetMapping(path = "/getNotCompInterview") + @Operation(summary = "면접 질문 조회", description = "면접 질문 조회") + @GetMapping(path = "/getQaList") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "OK") } ) - public InterviewNotCompRes getNotCompInterview( + public InterviewQaListRes getQaList( @Schema(description = "userId", example = "1", name = "userId") @RequestParam(name = "userId") Long userId, @Schema(description = "interviewId", example = "1", name = "interviewId") @RequestParam(name = "interviewId") Long interviewId ) { - return interviewService.selectNotCompInterview(userId, interviewId); + return interviewService.selectQaList(userId, interviewId); } + + @Operation(summary = "답변 초기화", description = "답변 초기화") + @PostMapping("/initQa") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = String.class))) + } + ) + public CommonResponse initQa(@RequestBody InterviewInitQaReq interviewInitQaReq) throws Exception { + return interviewService.initQa(interviewInitQaReq); + } + + @Operation(summary = "면접 결과 내보내기", description = "면접 결과 내보내기") + @GetMapping("/downloadInterview") + public void downloadInterview( + @Schema(description = "userId", example = "1", name = "userId") @RequestParam(name = "userId") Long userId, + @Schema(description = "interviewId", example = "1", name = "interviewId") @RequestParam(name = "interviewId") Long interviewId, + HttpServletResponse response + ) throws IOException { + interviewService.downloadInterview(userId, interviewId, response); + } + + + @Operation(summary = "피드백 재생성", description = "피드백 재생성") + @PostMapping("/generateFeedback") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = String.class))) + } + ) + public CommonResponse generateFeedback (@RequestBody FeedbackGenerateReq feedbackGenerateReq) throws Exception { + return interviewService.generateFeedback(feedbackGenerateReq); + } + + @Operation(summary = "답변 저장", description = "답변 저장") + @PostMapping("/insertAnswer") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = String.class))) + } + ) + public CommonResponse insertAnswer(@RequestBody QaAnswerInsertReq qaAnswerInsertReq) throws Exception { + return interviewService.insertAnswer(qaAnswerInsertReq); + } } diff --git a/src/main/java/com/chwipoClova/interview/entity/Interview.java b/src/main/java/com/chwipoClova/interview/entity/Interview.java index d2d629c..b4eaa86 100644 --- a/src/main/java/com/chwipoClova/interview/entity/Interview.java +++ b/src/main/java/com/chwipoClova/interview/entity/Interview.java @@ -1,5 +1,6 @@ package com.chwipoClova.interview.entity; +import com.chwipoClova.qa.entity.QaEditor; import com.chwipoClova.user.entity.User; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; @@ -40,6 +41,14 @@ public class Interview { @Schema(description = "채용공고 요약") private String recruitSummary; + @Column(name = "status") + @Schema(description = "상태 (0 : 미완료, 1 : 완료)") + private Integer status; + + @Column(name = "feedback") + @Schema(description = "면접관의속마음") + private String feedback; + @Column(name = "regDate") @Schema(description = "등록일") private Date regDate; @@ -54,4 +63,14 @@ public void prePersist() { this.regDate = new Date(); // 현재 날짜와 시간으로 등록일 설정 } + + public InterviewEditor.InterviewEditorBuilder toEditor() { + return InterviewEditor.builder() + .status(status); + } + + public void edit(InterviewEditor interviewEditor) { + status = interviewEditor.getStatus(); + } + } diff --git a/src/main/java/com/chwipoClova/interview/entity/InterviewEditor.java b/src/main/java/com/chwipoClova/interview/entity/InterviewEditor.java new file mode 100644 index 0000000..d497880 --- /dev/null +++ b/src/main/java/com/chwipoClova/interview/entity/InterviewEditor.java @@ -0,0 +1,16 @@ +package com.chwipoClova.interview.entity; + +import lombok.Builder; +import lombok.Getter; + + +@Getter +public class InterviewEditor { + + private Integer status; + + @Builder + public InterviewEditor(Integer status) { + this.status = status; + } +} diff --git a/src/main/java/com/chwipoClova/interview/request/InterviewFeedbackGenerateReq.java b/src/main/java/com/chwipoClova/interview/request/InterviewFeedbackGenerateReq.java new file mode 100644 index 0000000..5d1ac1f --- /dev/null +++ b/src/main/java/com/chwipoClova/interview/request/InterviewFeedbackGenerateReq.java @@ -0,0 +1,14 @@ +package com.chwipoClova.interview.request; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Data +public class InterviewFeedbackGenerateReq { + + @Schema(description = "유저 ID", example = "1", name = "userId") + private Long userId; + @Schema(description = "면접 ID", example = "1", name = "interviewId") + private Long interviewId; + +} diff --git a/src/main/java/com/chwipoClova/interview/request/InterviewInitQaReq.java b/src/main/java/com/chwipoClova/interview/request/InterviewInitQaReq.java new file mode 100644 index 0000000..ceb5c74 --- /dev/null +++ b/src/main/java/com/chwipoClova/interview/request/InterviewInitQaReq.java @@ -0,0 +1,12 @@ +package com.chwipoClova.interview.request; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Data +public class InterviewInitQaReq { + @Schema(description = "유저 ID", example = "1", name = "userId") + private Long userId; + @Schema(description = "면접 ID", example = "1", name = "interviewId") + private Long interviewId; +} diff --git a/src/main/java/com/chwipoClova/interview/request/InterviewQaAnswerInsertReq.java b/src/main/java/com/chwipoClova/interview/request/InterviewQaAnswerInsertReq.java new file mode 100644 index 0000000..c1c9416 --- /dev/null +++ b/src/main/java/com/chwipoClova/interview/request/InterviewQaAnswerInsertReq.java @@ -0,0 +1,20 @@ +package com.chwipoClova.interview.request; + +import com.chwipoClova.qa.request.QaAnswerDataInsertReq; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +@Data +public class InterviewQaAnswerInsertReq { + + @Schema(description = "유저 ID", example = "1", name = "userId") + private Long userId; + + @Schema(description = "면접 ID", example = "1", name = "interviewId") + private Long interviewId; + + @Schema(description = "답변데이터", name = "answerData") + private List answerData; +} diff --git a/src/main/java/com/chwipoClova/interview/response/InterviewListRes.java b/src/main/java/com/chwipoClova/interview/response/InterviewListRes.java index 3592d15..2001d40 100644 --- a/src/main/java/com/chwipoClova/interview/response/InterviewListRes.java +++ b/src/main/java/com/chwipoClova/interview/response/InterviewListRes.java @@ -25,6 +25,9 @@ public class InterviewListRes { @Schema(description = "답변개수", example = "1", name = "useCnt") private Integer useCnt; + @Schema(description = "완료여부(0: 미완성, 1: 완성)", example = "1", name = "status") + private Integer status; + @Schema(description = "등록일", example = "2023-12-09T10:13:17.838+00:00", name = "regDate") private Date regDate; } diff --git a/src/main/java/com/chwipoClova/interview/response/InterviewNotCompRes.java b/src/main/java/com/chwipoClova/interview/response/InterviewQaListRes.java similarity index 93% rename from src/main/java/com/chwipoClova/interview/response/InterviewNotCompRes.java rename to src/main/java/com/chwipoClova/interview/response/InterviewQaListRes.java index c95e29a..d516577 100644 --- a/src/main/java/com/chwipoClova/interview/response/InterviewNotCompRes.java +++ b/src/main/java/com/chwipoClova/interview/response/InterviewQaListRes.java @@ -5,12 +5,11 @@ import lombok.Builder; import lombok.Data; -import java.util.Date; import java.util.List; @Data @Builder -public class InterviewNotCompRes { +public class InterviewQaListRes { @Schema(description = "면접 ID", example = "1", name = "interviewId") private Long interviewId; diff --git a/src/main/java/com/chwipoClova/interview/response/InterviewRes.java b/src/main/java/com/chwipoClova/interview/response/InterviewRes.java index 496a1df..3cde3e0 100644 --- a/src/main/java/com/chwipoClova/interview/response/InterviewRes.java +++ b/src/main/java/com/chwipoClova/interview/response/InterviewRes.java @@ -20,8 +20,12 @@ public class InterviewRes { private Long userId; @Schema(description = "면접 제목", example = "삼성채용", name = "title") private String title; + @Schema(description = "완료여부(0 미완료, 1 완료)", example = "1", name = "status") + private Integer status; @Schema(description = "등록일", example = "2023-12-09T10:13:17.838+00:00", name = "regDate") private Date regDate; + @Schema(description = "면접관의속마음", example = "속마음1", name = "feedback") + private String feedback; @Schema(description = "질문데이터", name = "qaData") private List qaData; diff --git a/src/main/java/com/chwipoClova/interview/service/InterviewService.java b/src/main/java/com/chwipoClova/interview/service/InterviewService.java index a52d1a6..571e2b8 100644 --- a/src/main/java/com/chwipoClova/interview/service/InterviewService.java +++ b/src/main/java/com/chwipoClova/interview/service/InterviewService.java @@ -2,13 +2,20 @@ import com.chwipoClova.common.exception.CommonException; import com.chwipoClova.common.exception.ExceptionCode; +import com.chwipoClova.common.response.CommonResponse; +import com.chwipoClova.common.response.MessageCode; +import com.chwipoClova.feedback.request.FeedbackGenerateReq; +import com.chwipoClova.feedback.service.FeedbackService; import com.chwipoClova.interview.entity.Interview; import com.chwipoClova.interview.repository.InterviewRepository; +import com.chwipoClova.interview.request.InterviewFeedbackGenerateReq; +import com.chwipoClova.interview.request.InterviewInitQaReq; import com.chwipoClova.interview.request.InterviewInsertReq; import com.chwipoClova.interview.response.InterviewInsertRes; import com.chwipoClova.interview.response.InterviewListRes; -import com.chwipoClova.interview.response.InterviewNotCompRes; +import com.chwipoClova.interview.response.InterviewQaListRes; import com.chwipoClova.interview.response.InterviewRes; +import com.chwipoClova.qa.request.QaAnswerInsertReq; import com.chwipoClova.qa.request.QaQuestionInsertReq; import com.chwipoClova.qa.response.QaCountRes; import com.chwipoClova.qa.response.QaListForFeedbackRes; @@ -22,6 +29,7 @@ import com.chwipoClova.resume.repository.ResumeRepository; import com.chwipoClova.user.entity.User; import com.chwipoClova.user.repository.UserRepository; +import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; @@ -30,8 +38,10 @@ import org.springframework.web.multipart.MultipartFile; import java.io.IOException; +import java.net.URLEncoder; import java.util.ArrayList; import java.util.List; +import java.util.Map; @RequiredArgsConstructor @Service @@ -48,6 +58,8 @@ public class InterviewService { private final QaService qaService; + private final FeedbackService feedbackService; + @Value("${limit.size.interview}") private Integer interviewLimitSize; @@ -126,6 +138,8 @@ public InterviewRes selectInterview(Long userId, Long interviewId) { .interviewId(interview.getInterviewId()) .userId(user.getUserId()) .title(interview.getTitle()) + .status(interview.getStatus()) + .feedback(interview.getFeedback()) .regDate(interview.getRegDate()) .qaData(listForFeedbackResList) .build(); @@ -145,6 +159,7 @@ public List selectInterviewList(Long userId) { .title(interview.getTitle()) .useCnt(qaCountRes.getUseCnt()) .totalCnt(qaCountRes.getTotalCnt()) + .status(interview.getStatus()) .regDate(interview.getRegDate()) .build(); interviewListRes.add(interviewListRes1); @@ -153,7 +168,7 @@ public List selectInterviewList(Long userId) { return interviewListRes; } - public InterviewNotCompRes selectNotCompInterview(Long userId, Long interviewId) { + public InterviewQaListRes selectQaList(Long userId, Long interviewId) { userRepository.findById(userId).orElseThrow(() -> new CommonException(ExceptionCode.USER_NULL.getMessage(), ExceptionCode.USER_NULL.getCode())); interviewRepository.findByUserUserIdAndInterviewId(userId, interviewId).orElseThrow(() -> new CommonException(ExceptionCode.INTERVIEW_NULL.getMessage(), ExceptionCode.INTERVIEW_NULL.getCode())); @@ -163,7 +178,7 @@ public InterviewNotCompRes selectNotCompInterview(Long userId, Long interviewId) Long lastQaId = qaCountRes.getLastQaId(); List qaListResList = qaService.selectQaList(interviewId); - return InterviewNotCompRes.builder() + return InterviewQaListRes.builder() .interviewId(interviewId) .userId(userId) .totalCnt(totalCnt) @@ -172,4 +187,97 @@ public InterviewNotCompRes selectNotCompInterview(Long userId, Long interviewId) .qaData(qaListResList) .build(); } + + @Transactional + public CommonResponse initQa(InterviewInitQaReq interviewInitQaReq) { + Long userId = interviewInitQaReq.getUserId(); + Long interviewId = interviewInitQaReq.getInterviewId(); + userRepository.findById(userId).orElseThrow(() -> new CommonException(ExceptionCode.USER_NULL.getMessage(), ExceptionCode.USER_NULL.getCode())); + Interview interview = interviewRepository.findByUserUserIdAndInterviewId(userId, interviewId).orElseThrow(() -> new CommonException(ExceptionCode.INTERVIEW_NULL.getMessage(), ExceptionCode.INTERVIEW_NULL.getCode())); + + Integer status = interview.getStatus(); + + // 완료 된 질문은 사용 불가 + if (status == 1) { + throw new CommonException(ExceptionCode.INTERVIEW_COMPLETE.getMessage(), ExceptionCode.INTERVIEW_COMPLETE.getCode()); + } + + qaService.initQa(interviewId); + return new CommonResponse<>(MessageCode.OK.getCode(), null, MessageCode.OK.getMessage()); + } + + public void downloadInterview(Long userId, Long interviewId, HttpServletResponse response) throws IOException { + Interview interview = interviewRepository.findByUserUserIdAndInterviewId(userId, interviewId).orElseThrow(() -> new CommonException(ExceptionCode.INTERVIEW_NULL.getMessage(), ExceptionCode.INTERVIEW_NULL.getCode())); + + Integer status = interview.getStatus(); + + // 완료 된 질문은 사용 불가 + if (status == 1) { + throw new CommonException(ExceptionCode.INTERVIEW_COMPLETE.getMessage(), ExceptionCode.INTERVIEW_COMPLETE.getCode()); + } + + InterviewRes interviewRes = selectInterview(userId, interviewId); + + String title = interviewRes.getTitle(); + + String name = URLEncoder.encode(title, "UTF-8"); + + String filename = name + ".txt"; + + StringBuilder stringBuilder = new StringBuilder(); + + String feedback = interviewRes.getFeedback(); + + stringBuilder.append(title + "면접 결과"); + + stringBuilder.append("\n"); + stringBuilder.append("\n"); + + stringBuilder.append("면접 관의 속마음"); + stringBuilder.append("\n"); + stringBuilder.append(feedback); + + stringBuilder.append("\n"); + stringBuilder.append("\n"); + + stringBuilder.append("티키타카의 피드백"); + + stringBuilder.append("\n"); + stringBuilder.append("\n"); + + interviewRes.getQaData().stream().forEach(qaListForFeedbackRes -> { + stringBuilder.append(qaListForFeedbackRes.getFeedback1()); + stringBuilder.append("\n"); + + stringBuilder.append(qaListForFeedbackRes.getQuestion()); + stringBuilder.append("\n"); + + stringBuilder.append(qaListForFeedbackRes.getFeedback2()); + stringBuilder.append("\n"); + }); + + String content = stringBuilder.toString(); + + byte[] fileByte = content.getBytes(); + + response.setContentType("application/octet-stream"); + response.setCharacterEncoding("UTF-8"); + response.setContentLength(fileByte.length); + response.setHeader("Content-Disposition", "attachment; FileName=\"" + filename +"\";"); + response.setHeader("Access-Control-Expose-Headers", "X-Filename"); + response.setHeader("X-Filename", filename); + response.setHeader("Content-Transfer-Encoding", "binary"); + response.getOutputStream().write(fileByte); + + response.getOutputStream().flush(); + response.getOutputStream().close(); + } + + public CommonResponse generateFeedback(FeedbackGenerateReq feedbackGenerateReq) { + return feedbackService.generateFeedback(feedbackGenerateReq); + } + + public CommonResponse insertAnswer(QaAnswerInsertReq qaAnswerInsertReq) throws IOException { + return qaService.insertAnswer(qaAnswerInsertReq); + } } diff --git a/src/main/java/com/chwipoClova/qa/controller/QaController.java b/src/main/java/com/chwipoClova/qa/controller/QaController.java index 20cb724..1498e7c 100644 --- a/src/main/java/com/chwipoClova/qa/controller/QaController.java +++ b/src/main/java/com/chwipoClova/qa/controller/QaController.java @@ -25,13 +25,5 @@ public class QaController { private final QaService qaService; - @Operation(summary = "답변 저장", description = "답변 저장") - @PostMapping("/insertAnswer") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = String.class))) - } - ) - public CommonResponse insertAnswer(@RequestBody QaAnswerInsertReq qaAnswerInsertReq) throws Exception { - return qaService.insertAnswer(qaAnswerInsertReq); - } + } diff --git a/src/main/java/com/chwipoClova/qa/repository/QaRepository.java b/src/main/java/com/chwipoClova/qa/repository/QaRepository.java index 7ce2c76..0ff356a 100644 --- a/src/main/java/com/chwipoClova/qa/repository/QaRepository.java +++ b/src/main/java/com/chwipoClova/qa/repository/QaRepository.java @@ -3,6 +3,9 @@ import com.chwipoClova.qa.entity.Qa; import com.chwipoClova.resume.entity.Resume; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; import java.util.List; import java.util.Optional; @@ -13,4 +16,9 @@ public interface QaRepository extends JpaRepository { List findByInterviewInterviewIdOrderByQaId(Long interviewId); + Qa findFirstByInterviewInterviewIdOrderByQaIdDesc(Long interviewId); + + @Modifying + @Query(value = "update Qa q set q.answer = null where q.interviewId = :interviewId and answer is not null", nativeQuery = true) + int initQa(@Param("interviewId") Long interviewId); } diff --git a/src/main/java/com/chwipoClova/qa/response/QaListForFeedbackRes.java b/src/main/java/com/chwipoClova/qa/response/QaListForFeedbackRes.java index 55dab8f..1db7e00 100644 --- a/src/main/java/com/chwipoClova/qa/response/QaListForFeedbackRes.java +++ b/src/main/java/com/chwipoClova/qa/response/QaListForFeedbackRes.java @@ -30,6 +30,9 @@ public class QaListForFeedbackRes { @Schema(description = "수정일", example = "2023-12-09T10:13:17.838+00:00", name = "modifyDate") private Date modifyDate; - @Schema(description = "피드백 데이터", name = "feedbackData") - private List feedbackData; + @Schema(description = "피드백1 키워드", example = "키워드", name = "feedback1") + private String feedback1; + + @Schema(description = "피드백2 AI 답변", example = "AI 답변", name = "feedback2") + private String feedback2; } diff --git a/src/main/java/com/chwipoClova/qa/service/QaService.java b/src/main/java/com/chwipoClova/qa/service/QaService.java index d6d7a3c..83250d1 100644 --- a/src/main/java/com/chwipoClova/qa/service/QaService.java +++ b/src/main/java/com/chwipoClova/qa/service/QaService.java @@ -5,9 +5,9 @@ import com.chwipoClova.common.response.CommonResponse; import com.chwipoClova.common.response.MessageCode; import com.chwipoClova.feedback.request.FeedbackInsertReq; -import com.chwipoClova.feedback.response.FeedbackListRes; import com.chwipoClova.feedback.service.FeedbackService; import com.chwipoClova.interview.entity.Interview; +import com.chwipoClova.interview.entity.InterviewEditor; import com.chwipoClova.interview.repository.InterviewRepository; import com.chwipoClova.qa.entity.Qa; import com.chwipoClova.qa.entity.QaEditor; @@ -28,6 +28,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; @@ -76,12 +77,16 @@ public List insertQaQuestionList(List public CommonResponse insertAnswer(QaAnswerInsertReq qaAnswerInsertReq) throws IOException { Long userId = qaAnswerInsertReq.getUserId(); Long interviewId = qaAnswerInsertReq.getInterviewId(); - interviewRepository.findByUserUserIdAndInterviewId(userId, interviewId).orElseThrow(() -> new CommonException(ExceptionCode.INTERVIEW_NULL.getMessage(), ExceptionCode.INTERVIEW_NULL.getCode())); + Interview interview = interviewRepository.findByUserUserIdAndInterviewId(userId, interviewId).orElseThrow(() -> new CommonException(ExceptionCode.INTERVIEW_NULL.getMessage(), ExceptionCode.INTERVIEW_NULL.getCode())); List qaAnswerDataInsertReqList = qaAnswerInsertReq.getAnswerData(); List feedbackInsertListReq = new ArrayList<>(); + Qa lastQa = qaRepository.findFirstByInterviewInterviewIdOrderByQaIdDesc(interviewId); + Long lastQaId = lastQa.getQaId(); + + AtomicBoolean lastCkAtomic = new AtomicBoolean(false); qaAnswerDataInsertReqList.stream().forEach(qaAnswerDataInsertReq -> { String answer = qaAnswerDataInsertReq.getAnswer(); @@ -93,6 +98,10 @@ public CommonResponse insertAnswer(QaAnswerInsertReq qaAnswerInsertReq) throws I .build(); qa.edit(qaEditor); + if (lastQaId == qa.getQaId()) { + lastCkAtomic.set(true); + } + // 피드백 정보 FeedbackInsertReq feedbackInsertReq = new FeedbackInsertReq(); feedbackInsertReq.setQaId(qa.getQaId()); @@ -102,8 +111,17 @@ public CommonResponse insertAnswer(QaAnswerInsertReq qaAnswerInsertReq) throws I } }); - // 피드백 요청 및 등록 - feedbackService.insertFeedback(feedbackInsertListReq); + // 마지막 답변이 있을 경우 면접 완료 처리 및 피드백 생성 + Boolean lastCk = lastCkAtomic.get(); + if (lastCk) { + // 피드백 요청 및 등록 + feedbackService.insertFeedback(feedbackInsertListReq); + + // 면접 완료 처리 + InterviewEditor.InterviewEditorBuilder editorBuilder = interview.toEditor(); + InterviewEditor interviewEditor = editorBuilder.status(1).build(); + interview.edit(interviewEditor); + } return new CommonResponse<>(MessageCode.OK.getCode(), null, MessageCode.OK.getMessage()); } @@ -132,7 +150,17 @@ public List selectQaListForFeedback(Long interviewId) { List listForFeedbackResList = new ArrayList<>(); qaListRes.stream().forEach(qaListRes1 -> { - List feedbackListRes = feedbackService.selectFeedbackList(qaListRes1.getQaId()); + AtomicReference feedback1 = new AtomicReference<>(""); + AtomicReference feedback2 = new AtomicReference<>(""); + feedbackService.selectFeedbackList(qaListRes1.getQaId()).stream().forEach(feedbackListRes -> { + Integer type = feedbackListRes.getType(); + if (type == 1) { + feedback1.set(feedbackListRes.getContent()); + } else if (type == 2) { + feedback2.set(feedbackListRes.getContent()); + } + }); + QaListForFeedbackRes qalistForFeedbackRes = QaListForFeedbackRes.builder() .interviewId(qaListRes1.getInterviewId()) .qaId(qaListRes1.getQaId()) @@ -140,7 +168,8 @@ public List selectQaListForFeedback(Long interviewId) { .answer(qaListRes1.getAnswer()) .regDate(qaListRes1.getRegDate()) .modifyDate(qaListRes1.getModifyDate()) - .feedbackData(feedbackListRes) + .feedback1(feedback1.get()) + .feedback2(feedback2.get()) .build(); listForFeedbackResList.add(qalistForFeedbackRes); }); @@ -170,4 +199,8 @@ public QaCountRes selectQaListUseCount(Long interviewId) { .build(); } + @Transactional + public void initQa(Long interviewId) { + qaRepository.initQa(interviewId); + } } diff --git a/src/main/java/com/chwipoClova/user/controller/UserController.java b/src/main/java/com/chwipoClova/user/controller/UserController.java index e24a521..8986f78 100644 --- a/src/main/java/com/chwipoClova/user/controller/UserController.java +++ b/src/main/java/com/chwipoClova/user/controller/UserController.java @@ -1,18 +1,22 @@ package com.chwipoClova.user.controller; +import com.chwipoClova.common.response.CommonMsgResponse; import com.chwipoClova.common.response.CommonResponse; +import com.chwipoClova.common.response.MessageCode; import com.chwipoClova.user.response.UserInfoRes; import com.chwipoClova.user.response.UserLoginRes; import com.chwipoClova.user.response.UserSnsUrlRes; import com.chwipoClova.user.service.UserService; import io.swagger.v3.oas.annotations.Hidden; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotBlank; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.GetMapping; @@ -72,4 +76,16 @@ public CommonResponse kakaoLogin(@Schema(description = "로그인코드", exampl public String kakaoCallback(@Schema(description = "로그인코드", example = "1", name = "code") @RequestParam(name = "code") String code, HttpServletResponse response) throws Exception { return code; } + + @Operation(summary = "로그아웃", description = "로그아웃") + @GetMapping("/logout") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = String.class))) + } + ) + public CommonResponse logout(@Schema(description = "유저 ID", example = "1", name = "userId") @NotBlank(message = "UserID를 입력해주세요.") Long userId, + @Parameter(hidden = true) HttpServletResponse response + ) { + return userService.logout(response, userId); + } } diff --git a/src/main/java/com/chwipoClova/user/service/UserService.java b/src/main/java/com/chwipoClova/user/service/UserService.java index 954779e..bccea7d 100644 --- a/src/main/java/com/chwipoClova/user/service/UserService.java +++ b/src/main/java/com/chwipoClova/user/service/UserService.java @@ -203,4 +203,11 @@ public UserInfoRes selectUserInfo(String email) { .modifyDate(user.getModifyDate()) .build(); } + + public CommonResponse logout(HttpServletResponse response, Long userId) { + tokenRepository.deleteById(userId); + jwtUtil.setHeaderAccessToken(response, ""); + jwtUtil.setHeaderRefreshToken(response, ""); + return new CommonResponse<>(MessageCode.OK.getCode(), null, MessageCode.OK.getMessage()); + } }