diff --git a/layer-api/src/main/java/org/layer/domain/retrospect/controller/RetrospectApi.java b/layer-api/src/main/java/org/layer/domain/retrospect/controller/RetrospectApi.java index cb88c7df..c203b251 100644 --- a/layer-api/src/main/java/org/layer/domain/retrospect/controller/RetrospectApi.java +++ b/layer-api/src/main/java/org/layer/domain/retrospect/controller/RetrospectApi.java @@ -1,6 +1,12 @@ package org.layer.domain.retrospect.controller; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.headers.Header; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.ExampleObject; +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.validation.Valid; @@ -31,4 +37,24 @@ ResponseEntity updateRetrospect(@PathVariable("spaceI @Operation(summary = "회고 삭제", description = "특정 팀 스페이스에서 작성했던 회고를 삭제하는 기능입니다.") ResponseEntity deleteRetrospect(@PathVariable("spaceId") Long spaceId, @PathVariable("retrospectId") Long retrospectId, @MemberId Long memberId); + + @Operation(summary = "회고 마감", description = "특정 팀 스페이스에서 작성했던 회고를 마감하는 기능입니다.
Note: 스페이스 내 모든 인원이 작성해야 가능합니다.") + @ApiResponses({ + @ApiResponse(responseCode = "200", description = "회고 마감 성공", + content = @Content(mediaType = "application/json")), + @ApiResponse(responseCode = "400", description = "회고 마감 실패", + content = @Content(mediaType = "application/json", examples = { + @ExampleObject(name = "회고 마감 실패", value = """ + { + "name": "NOT_COMPLETE_RETROSPECT_MEMBER", + "message": "회고를 작성하지 않은 팀원이 있습니다." + } + """ + ) + })) + }) + ResponseEntity closeRetrospect( + @PathVariable("spaceId") Long spaceId, + @PathVariable("retrospectId") Long retrospectId, + @MemberId Long memberId); } diff --git a/layer-api/src/main/java/org/layer/domain/retrospect/controller/RetrospectController.java b/layer-api/src/main/java/org/layer/domain/retrospect/controller/RetrospectController.java index f3d334c3..28f5f351 100644 --- a/layer-api/src/main/java/org/layer/domain/retrospect/controller/RetrospectController.java +++ b/layer-api/src/main/java/org/layer/domain/retrospect/controller/RetrospectController.java @@ -75,4 +75,16 @@ public ResponseEntity deleteRetrospect(@PathVariable( return ResponseEntity.ok().build(); } + @Override + @PatchMapping("/{retrospectId}/close") + public ResponseEntity closeRetrospect( + @PathVariable("spaceId") Long spaceId, + @PathVariable("retrospectId") Long retrospectId, + @MemberId Long memberId) { + + retrospectService.closeRetrospect(spaceId, retrospectId, memberId); + + return ResponseEntity.ok().build(); + } + } diff --git a/layer-api/src/main/java/org/layer/domain/retrospect/service/RetrospectService.java b/layer-api/src/main/java/org/layer/domain/retrospect/service/RetrospectService.java index 66640108..a8080733 100644 --- a/layer-api/src/main/java/org/layer/domain/retrospect/service/RetrospectService.java +++ b/layer-api/src/main/java/org/layer/domain/retrospect/service/RetrospectService.java @@ -1,5 +1,7 @@ package org.layer.domain.retrospect.service; +import static org.layer.common.exception.RetrospectExceptionType.*; + import lombok.RequiredArgsConstructor; import org.layer.domain.answer.entity.Answers; @@ -18,6 +20,7 @@ import org.layer.domain.retrospect.controller.dto.request.RetrospectUpdateRequest; import org.layer.domain.retrospect.entity.Retrospect; import org.layer.domain.retrospect.entity.RetrospectStatus; +import org.layer.domain.retrospect.exception.RetrospectException; import org.layer.domain.retrospect.repository.RetrospectRepository; import org.layer.domain.retrospect.service.dto.response.RetrospectGetServiceResponse; import org.layer.domain.retrospect.service.dto.response.RetrospectListGetServiceResponse; @@ -27,6 +30,7 @@ import org.layer.domain.space.repository.SpaceRepository; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.PathVariable; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; @@ -149,4 +153,26 @@ public void deleteRetrospect(Long spaceId, Long retrospectId, Long memberId) { Retrospect retrospect = retrospectRepository.findByIdOrThrow(retrospectId); retrospectRepository.delete(retrospect); } + + @Transactional + public void closeRetrospect(Long spaceId, Long retrospectId, Long memberId) { + // 해당 스페이스 팀원인지 검증 + Team team = new Team(memberSpaceRelationRepository.findAllBySpaceId(spaceId)); + team.validateTeamMembership(memberId); + + // 팀장인지 검증 + Space space = spaceRepository.findByIdOrThrow(spaceId); + space.isLeaderSpace(memberId); + + // 팀원 모두 회고를 작성했는지 검증 + Retrospect retrospect = retrospectRepository.findByIdOrThrow(retrospectId); + + Answers answers = new Answers(answerRepository.findAllByRetrospectId(retrospectId)); + + if (answers.getWriteCount() != team.getTeamMemberCount()) { + throw new RetrospectException(NOT_COMPLETE_RETROSPECT_MEMBER); + } + + retrospect.updateRetrospectStatus(RetrospectStatus.DONE); + } } diff --git a/layer-common/src/main/java/org/layer/common/exception/RetrospectExceptionType.java b/layer-common/src/main/java/org/layer/common/exception/RetrospectExceptionType.java index 6f85cea0..8d60b615 100644 --- a/layer-common/src/main/java/org/layer/common/exception/RetrospectExceptionType.java +++ b/layer-common/src/main/java/org/layer/common/exception/RetrospectExceptionType.java @@ -7,6 +7,7 @@ @RequiredArgsConstructor public enum RetrospectExceptionType implements ExceptionType { INVALID_DEADLINE(HttpStatus.BAD_REQUEST, "회고 마감기한이 유효하지 않습니다."), + NOT_COMPLETE_RETROSPECT_MEMBER(HttpStatus.BAD_REQUEST, "회고를 작성하지 않은 팀원이 있습니다."), DEADLINE_PASSED(HttpStatus.BAD_REQUEST, "회고 마감기한이 지났습니다."), DEADLINE_NOT_PASSED(HttpStatus.BAD_REQUEST, "회고가 마감되지 않았습니다."), NOT_PROCEEDING_RETROSPECT(HttpStatus.BAD_REQUEST, "진행중인 회고가 아닙니다."), diff --git a/layer-domain/src/main/java/org/layer/domain/retrospect/entity/Retrospect.java b/layer-domain/src/main/java/org/layer/domain/retrospect/entity/Retrospect.java index c14a4c53..0bac6f16 100644 --- a/layer-domain/src/main/java/org/layer/domain/retrospect/entity/Retrospect.java +++ b/layer-domain/src/main/java/org/layer/domain/retrospect/entity/Retrospect.java @@ -82,4 +82,10 @@ public void updateRetrospect(String title, String introduction, LocalDateTime de this.introduction = introduction; this.deadline = deadline; } + + public void updateRetrospectStatus(RetrospectStatus retrospectStatus){ + isProceedingRetrospect(); + + this.retrospectStatus = retrospectStatus; + } } diff --git a/layer-domain/src/main/java/org/layer/domain/space/entity/Team.java b/layer-domain/src/main/java/org/layer/domain/space/entity/Team.java index 580ea533..35b8b20c 100644 --- a/layer-domain/src/main/java/org/layer/domain/space/entity/Team.java +++ b/layer-domain/src/main/java/org/layer/domain/space/entity/Team.java @@ -19,7 +19,7 @@ public void validateTeamMembership(Long memberId){ .orElseThrow(() -> new MemberSpaceRelationException(NOT_FOUND_MEMBER_SPACE_RELATION)); } - public int getTeamMemberCount(){ + public long getTeamMemberCount(){ return memberSpaceRelations.size(); } }