From 7b8aa34ff6239f7547b00a41daedde72a2f8a6cc Mon Sep 17 00:00:00 2001 From: kwonhee1 Date: Wed, 17 Sep 2025 20:15:24 +0900 Subject: [PATCH 1/4] feat project community answer --- .../ProjectCommunityController.java | 45 +++++++++++--- .../entity/ProjectCommunityAnswerEntity.java | 6 ++ .../ProjectCommunityAskRepository.java | 2 +- .../ProjectCommunityAnswerService.java | 61 +++++++++++++++++++ .../service/ProjectCommunityAskService.java | 2 +- .../service/ProjectValidateService.java | 15 ++++- 6 files changed, 121 insertions(+), 10 deletions(-) create mode 100644 src/main/java/NextLevel/demo/project/community/service/ProjectCommunityAnswerService.java diff --git a/src/main/java/NextLevel/demo/project/community/controller/ProjectCommunityController.java b/src/main/java/NextLevel/demo/project/community/controller/ProjectCommunityController.java index 348ef1f..809c3ff 100644 --- a/src/main/java/NextLevel/demo/project/community/controller/ProjectCommunityController.java +++ b/src/main/java/NextLevel/demo/project/community/controller/ProjectCommunityController.java @@ -2,6 +2,7 @@ import NextLevel.demo.common.SuccessResponse; import NextLevel.demo.project.community.dto.request.SaveCommunityDto; +import NextLevel.demo.project.community.service.ProjectCommunityAnswerService; import NextLevel.demo.project.community.service.ProjectCommunityAskService; import NextLevel.demo.util.jwt.JWTUtil; import jakarta.validation.Valid; @@ -20,29 +21,59 @@ @RequiredArgsConstructor public class ProjectCommunityController { - private final ProjectCommunityAskService communityService; + private final ProjectCommunityAskService askService; + private final ProjectCommunityAnswerService answerService; - // 생성만 + // ask 관련 + + // 생성 @PostMapping("/api1/project/{projectId}/community") - public ResponseEntity saveProjectCommunity(@PathVariable("projectId") Long projectId, @RequestBody @Valid SaveCommunityDto dto) { + public ResponseEntity saveProjectCommunityAsk(@PathVariable("projectId") Long projectId, @RequestBody @Valid SaveCommunityDto dto) { dto.setUserId(JWTUtil.getUserIdFromSecurityContext()); dto.setId(projectId); - communityService.create(dto); + askService.create(dto); return ResponseEntity.status(HttpStatus.OK).body(new SuccessResponse("success", null)); } // 수정 @PostMapping("/api1/project/community/{communityId}") - public ResponseEntity updateProjectCommunity(@PathVariable("communityId") Long communityId, @RequestBody @Valid SaveCommunityDto dto) { + public ResponseEntity updateProjectCommunityAsk(@PathVariable("communityId") Long communityId, @RequestBody @Valid SaveCommunityDto dto) { dto.setUserId(JWTUtil.getUserIdFromSecurityContext()); dto.setId(communityId); - communityService.update(dto); + askService.update(dto); return ResponseEntity.status(HttpStatus.OK).body(new SuccessResponse("success", null)); } @DeleteMapping("/api1/project/community/{communityId}") public ResponseEntity deleteProjectCommunity(@PathVariable("communityId") Long communityId) { - communityService.delete(communityId,JWTUtil.getUserIdFromSecurityContext()); + askService.delete(communityId,JWTUtil.getUserIdFromSecurityContext()); + return ResponseEntity.status(HttpStatus.OK).body(new SuccessResponse("success", null)); + } + + // answer 관련 + + // 생성 + @PostMapping("/api1/project/{askId}/community/answer") + public ResponseEntity saveProjectCommunityAnswer(@PathVariable("askId") Long askId, @RequestBody @Valid SaveCommunityDto dto) { + dto.setUserId(JWTUtil.getUserIdFromSecurityContext()); + dto.setId(askId); + answerService.addAnswer(dto); + return ResponseEntity.status(HttpStatus.OK).body(new SuccessResponse("success", null)); + } + + // 수정 + @PostMapping("/api1/project/community/{answerId}/answer") + public ResponseEntity updateProjectCommunityAnswer(@PathVariable("answerId") Long answerId, @RequestBody @Valid SaveCommunityDto dto) { + dto.setUserId(JWTUtil.getUserIdFromSecurityContext()); + dto.setId(answerId); + answerService.updateAnswer(dto); return ResponseEntity.status(HttpStatus.OK).body(new SuccessResponse("success", null)); } + + @DeleteMapping("/api1/project/community/{answerId}/answer") + public ResponseEntity deleteProjectCommunityAnswer(@PathVariable("answerId") Long answerId) { + answerService.deleteAnswer(answerId,JWTUtil.getUserIdFromSecurityContext()); + return ResponseEntity.status(HttpStatus.OK).body(new SuccessResponse("success", null)); + } + } diff --git a/src/main/java/NextLevel/demo/project/community/entity/ProjectCommunityAnswerEntity.java b/src/main/java/NextLevel/demo/project/community/entity/ProjectCommunityAnswerEntity.java index ee3f2d6..5e5292b 100644 --- a/src/main/java/NextLevel/demo/project/community/entity/ProjectCommunityAnswerEntity.java +++ b/src/main/java/NextLevel/demo/project/community/entity/ProjectCommunityAnswerEntity.java @@ -1,6 +1,7 @@ package NextLevel.demo.project.community.entity; import NextLevel.demo.BasedEntity; +import NextLevel.demo.project.community.dto.request.SaveCommunityDto; import NextLevel.demo.user.entity.UserEntity; import jakarta.persistence.*; import lombok.AllArgsConstructor; @@ -31,4 +32,9 @@ public class ProjectCommunityAnswerEntity extends BasedEntity { @JoinColumn(name = "ask_id", nullable = false) private ProjectCommunityAskEntity ask; + public void update(SaveCommunityDto dto) { + if(dto.getContent() != null && !dto.getContent().isEmpty()) + this.content = dto.getContent(); + } + } diff --git a/src/main/java/NextLevel/demo/project/community/repository/ProjectCommunityAskRepository.java b/src/main/java/NextLevel/demo/project/community/repository/ProjectCommunityAskRepository.java index efd9791..8945daa 100644 --- a/src/main/java/NextLevel/demo/project/community/repository/ProjectCommunityAskRepository.java +++ b/src/main/java/NextLevel/demo/project/community/repository/ProjectCommunityAskRepository.java @@ -10,6 +10,6 @@ public interface ProjectCommunityAskRepository extends JpaRepository { @Query("select ask from ProjectCommunityAskEntity ask left join fetch ask.answer where ask.project.id = :projectId") - List findAllByProjectId(@Param("projectId") Long projectId); + List findAllWithAnswerByProjectId(@Param("projectId") Long projectId); } diff --git a/src/main/java/NextLevel/demo/project/community/service/ProjectCommunityAnswerService.java b/src/main/java/NextLevel/demo/project/community/service/ProjectCommunityAnswerService.java new file mode 100644 index 0000000..9ffcd49 --- /dev/null +++ b/src/main/java/NextLevel/demo/project/community/service/ProjectCommunityAnswerService.java @@ -0,0 +1,61 @@ +package NextLevel.demo.project.community.service; + +import NextLevel.demo.exception.CustomException; +import NextLevel.demo.exception.ErrorCode; +import NextLevel.demo.project.community.dto.request.SaveCommunityDto; +import NextLevel.demo.project.community.entity.ProjectCommunityAnswerEntity; +import NextLevel.demo.project.community.entity.ProjectCommunityAskEntity; +import NextLevel.demo.project.community.repository.ProjectCommunityAnswerRepository; +import NextLevel.demo.project.community.repository.ProjectCommunityAskRepository; +import NextLevel.demo.project.project.service.ProjectValidateService; +import NextLevel.demo.user.entity.UserEntity; +import NextLevel.demo.user.service.UserValidateService; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +public class ProjectCommunityAnswerService { + + private final ProjectValidateService projectValidateService; + private final UserValidateService userValidateService; + + private final ProjectCommunityAnswerRepository projectCommunityAnswerRepository; + private final ProjectCommunityAskRepository projectCommunityAskRepository; + + @Transactional + public void addAnswer(SaveCommunityDto dto) { + Long askId = dto.getId(); + ProjectCommunityAskEntity ask = projectCommunityAskRepository.findById(askId).orElseThrow( + ()->{return new CustomException(ErrorCode.NOT_FOUND, "community");} + ); + UserEntity user = userValidateService.getUserInfo(dto.getUserId()); + + projectValidateService.validateAuthor(ask.getProject(), user); + + projectCommunityAnswerRepository.save(dto.toAnswerEntity(user, ask)); + } + + @Transactional + public void updateAnswer(SaveCommunityDto dto) { + Long answerId = dto.getId(); + ProjectCommunityAnswerEntity answer = projectCommunityAnswerRepository.findById(answerId).orElseThrow( + ()->{return new CustomException(ErrorCode.NOT_FOUND, "community");} + ); + UserEntity user = userValidateService.getUserInfo(dto.getUserId()); + projectValidateService.validateAuthor(answer.getAsk().getProject(), user); + answer.update(dto); + } + + @Transactional + public void deleteAnswer(Long answerId, Long userId) { + ProjectCommunityAnswerEntity answer = projectCommunityAnswerRepository.findById(answerId).orElseThrow( + ()->{return new CustomException(ErrorCode.NOT_FOUND, "community");} + ); + UserEntity user = userValidateService.getUserInfo(userId); + projectValidateService.validateAuthor(answer.getAsk().getProject(), user); + projectCommunityAnswerRepository.deleteById(answerId); + } + +} diff --git a/src/main/java/NextLevel/demo/project/community/service/ProjectCommunityAskService.java b/src/main/java/NextLevel/demo/project/community/service/ProjectCommunityAskService.java index 0ee802d..c820c2a 100644 --- a/src/main/java/NextLevel/demo/project/community/service/ProjectCommunityAskService.java +++ b/src/main/java/NextLevel/demo/project/community/service/ProjectCommunityAskService.java @@ -52,7 +52,7 @@ public void update(SaveCommunityDto dto) { @Transactional public ResponseCommunityListDto selectAll(Long projectId) { ProjectEntity project = projectValidateService.getProjectEntity(projectId); - List asks = projectCommunityAskRepository.findAllByProjectId(project.getId()); + List asks = projectCommunityAskRepository.findAllWithAnswerByProjectId(project.getId()); return new ResponseCommunityListDto(asks); } diff --git a/src/main/java/NextLevel/demo/project/project/service/ProjectValidateService.java b/src/main/java/NextLevel/demo/project/project/service/ProjectValidateService.java index c2d63ed..b8ecb82 100644 --- a/src/main/java/NextLevel/demo/project/project/service/ProjectValidateService.java +++ b/src/main/java/NextLevel/demo/project/project/service/ProjectValidateService.java @@ -4,6 +4,7 @@ import NextLevel.demo.exception.ErrorCode; import NextLevel.demo.project.project.entity.ProjectEntity; import NextLevel.demo.project.project.repository.ProjectRepository; +import NextLevel.demo.user.entity.UserEntity; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -20,9 +21,21 @@ public ProjectEntity getProjectEntity(Long id) { public ProjectEntity validateAuthor(Long projectId, Long userId) { ProjectEntity project = getProjectEntity(projectId); - if(project.getUser().getId() != userId){ + if(!project.getUser().getId().equals(userId)){ throw new CustomException(ErrorCode.NOT_AUTHOR); } return project; } + + public void validateAuthor(ProjectEntity project, Long userId) { + if(!project.getUser().getId().equals(userId)){ + throw new CustomException(ErrorCode.NOT_AUTHOR); + } + } + + public void validateAuthor(ProjectEntity project, UserEntity user) { + if(!project.getUser().getId().equals(user.getId())){ + throw new CustomException(ErrorCode.NOT_AUTHOR); + } + } } From 1b7f61bdc1767e6767825438f4c4417e24d0f86e Mon Sep 17 00:00:00 2001 From: kwonhee1 Date: Wed, 17 Sep 2025 20:18:25 +0900 Subject: [PATCH 2/4] =?UTF-8?q?chore=20:=20=EC=A3=BC=EC=84=9D=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../community/controller/ProjectCommunityController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/NextLevel/demo/project/community/controller/ProjectCommunityController.java b/src/main/java/NextLevel/demo/project/community/controller/ProjectCommunityController.java index 809c3ff..2554072 100644 --- a/src/main/java/NextLevel/demo/project/community/controller/ProjectCommunityController.java +++ b/src/main/java/NextLevel/demo/project/community/controller/ProjectCommunityController.java @@ -51,7 +51,7 @@ public ResponseEntity deleteProjectCommunity(@PathVariable("communityId") Lon } // answer 관련 - + // 생성 @PostMapping("/api1/project/{askId}/community/answer") public ResponseEntity saveProjectCommunityAnswer(@PathVariable("askId") Long askId, @RequestBody @Valid SaveCommunityDto dto) { From d610d4fc4bcf00c276280b7458b077370ee3fb01 Mon Sep 17 00:00:00 2001 From: kwonhee1 Date: Sat, 20 Sep 2025 01:19:29 +0900 Subject: [PATCH 3/4] fix : cascade --- .../community/entity/ProjectCommunityAskEntity.java | 4 +++- .../community/service/ProjectCommunityAnswerService.java | 7 +++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/main/java/NextLevel/demo/project/community/entity/ProjectCommunityAskEntity.java b/src/main/java/NextLevel/demo/project/community/entity/ProjectCommunityAskEntity.java index fc24aa3..b1ba2b1 100644 --- a/src/main/java/NextLevel/demo/project/community/entity/ProjectCommunityAskEntity.java +++ b/src/main/java/NextLevel/demo/project/community/entity/ProjectCommunityAskEntity.java @@ -36,7 +36,7 @@ public class ProjectCommunityAskEntity extends BasedEntity { @JoinColumn(name = "user_id", nullable = false) private UserEntity user; - @OneToOne(mappedBy = "ask") + @OneToOne(mappedBy = "ask", cascade = {CascadeType.REMOVE}) private ProjectCommunityAnswerEntity answer; public void update(SaveCommunityDto dto) { @@ -44,4 +44,6 @@ public void update(SaveCommunityDto dto) { this.content = dto.getContent(); } + public void setNoAnswer() { answer = null; } + } diff --git a/src/main/java/NextLevel/demo/project/community/service/ProjectCommunityAnswerService.java b/src/main/java/NextLevel/demo/project/community/service/ProjectCommunityAnswerService.java index 9ffcd49..343e61d 100644 --- a/src/main/java/NextLevel/demo/project/community/service/ProjectCommunityAnswerService.java +++ b/src/main/java/NextLevel/demo/project/community/service/ProjectCommunityAnswerService.java @@ -34,6 +34,12 @@ public void addAnswer(SaveCommunityDto dto) { projectValidateService.validateAuthor(ask.getProject(), user); + if(ask.getAnswer() != null) { + dto.setId(ask.getAnswer().getId()); + updateAnswer(dto); + return; + } + projectCommunityAnswerRepository.save(dto.toAnswerEntity(user, ask)); } @@ -55,6 +61,7 @@ public void deleteAnswer(Long answerId, Long userId) { ); UserEntity user = userValidateService.getUserInfo(userId); projectValidateService.validateAuthor(answer.getAsk().getProject(), user); + answer.getAsk().setNoAnswer(); projectCommunityAnswerRepository.deleteById(answerId); } From 7267e579463170b1fb94b4bbbb93793474203a2c Mon Sep 17 00:00:00 2001 From: kwonhee1 Date: Sat, 20 Sep 2025 01:31:42 +0900 Subject: [PATCH 4/4] merge --- .../community/controller/ProjectCommunityController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/NextLevel/demo/project/community/controller/ProjectCommunityController.java b/src/main/java/NextLevel/demo/project/community/controller/ProjectCommunityController.java index 8ecbb46..a2fdc5f 100644 --- a/src/main/java/NextLevel/demo/project/community/controller/ProjectCommunityController.java +++ b/src/main/java/NextLevel/demo/project/community/controller/ProjectCommunityController.java @@ -27,7 +27,7 @@ public class ProjectCommunityController { // list @GetMapping("/public/project/{projectId}/community") public ResponseEntity getProjectCommunity(@PathVariable Long projectId) { - return ResponseEntity.ok().body(new SuccessResponse("success", new ResponseCommunityListDto(communityService.selectAll(projectId)))); + return ResponseEntity.ok().body(new SuccessResponse("success", new ResponseCommunityListDto(askService.selectAll(projectId)))); } // 생성