diff --git a/backend/src/main/java/com/ody/mate/controller/MateControllerSwagger.java b/backend/src/main/java/com/ody/mate/controller/MateControllerSwagger.java index acc318f82..104762267 100644 --- a/backend/src/main/java/com/ody/mate/controller/MateControllerSwagger.java +++ b/backend/src/main/java/com/ody/mate/controller/MateControllerSwagger.java @@ -22,12 +22,12 @@ public interface MateControllerSwagger { @Operation( - summary = "모임 참여", + summary = "약속 참여", requestBody = @RequestBody(content = @Content(schema = @Schema(implementation = MateSaveRequest.class))), responses = { @ApiResponse( responseCode = "201", - description = "모임 참여 성공", + description = "약속 참여 성공", content = @Content(schema = @Schema(implementation = MeetingSaveResponse.class)) ) } diff --git a/backend/src/main/java/com/ody/meeting/controller/MeetingController.java b/backend/src/main/java/com/ody/meeting/controller/MeetingController.java index ef98fedf9..2602314e5 100644 --- a/backend/src/main/java/com/ody/meeting/controller/MeetingController.java +++ b/backend/src/main/java/com/ody/meeting/controller/MeetingController.java @@ -55,21 +55,11 @@ public ResponseEntity saveV1( @AuthMember Member member, @Valid @RequestBody MeetingSaveRequestV1 meetingSaveRequestV1 ) { - MeetingSaveResponseV1 meetingSaveResponseV1 = new MeetingSaveResponseV1( - 1L, - "우테코 16조", - LocalDate.parse("2024-07-15"), - LocalTime.parse("14:00"), - "서울 송파구 올림픽로 35다길 42", - "37.515298", - "127.103113", - "초대코드" - ); - + MeetingSaveResponseV1 meetingSaveResponseV1 = meetingService.saveV1(meetingSaveRequestV1); return ResponseEntity.status(HttpStatus.CREATED) .body(meetingSaveResponseV1); } - + @GetMapping("/v1/meetings/{meetingId}") public ResponseEntity findMeetingWithMates( @AuthMember Member member, diff --git a/backend/src/main/java/com/ody/meeting/controller/MeetingControllerSwagger.java b/backend/src/main/java/com/ody/meeting/controller/MeetingControllerSwagger.java index cb3260f73..8111ca80b 100644 --- a/backend/src/main/java/com/ody/meeting/controller/MeetingControllerSwagger.java +++ b/backend/src/main/java/com/ody/meeting/controller/MeetingControllerSwagger.java @@ -12,6 +12,7 @@ import com.ody.notification.dto.response.NotiLogFindResponses; import com.ody.swagger.annotation.ErrorCode400; import com.ody.swagger.annotation.ErrorCode401; +import com.ody.swagger.annotation.ErrorCode404; import com.ody.swagger.annotation.ErrorCode500; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; @@ -29,6 +30,7 @@ public interface MeetingControllerSwagger { @Operation( + deprecated = true, summary = "약속 개설", requestBody = @RequestBody(content = @Content(schema = @Schema(implementation = MeetingSaveRequest.class))), responses = { @@ -103,20 +105,15 @@ ResponseEntity save( summary = "초대코드 유효성 검사", responses = { @ApiResponse(responseCode = "200", description = "유효한 초대 코드"), - @ApiResponse( - responseCode = "404", - description = "유효하지 않은 초대코드", - content = @Content(schema = @Schema(implementation = ProblemDetail.class)) - ) } ) @ErrorCode400 @ErrorCode401 + @ErrorCode404(description = "유효하지 않은 초대코드") @ErrorCode500 ResponseEntity validateInviteCode(@Parameter(hidden = true) Member member, String inviteCode); @Operation( - deprecated = true, summary = "약속 개설", requestBody = @RequestBody(content = @Content(schema = @Schema(implementation = MeetingSaveRequestV1.class))), responses = { @@ -148,15 +145,11 @@ ResponseEntity saveV1( responseCode = "400", description = "클라이언트 입력 오류 또는 약속 시간 30분 전보다 이른 시간에 조회 시도 시", content = @Content(schema = @Schema(implementation = ProblemDetail.class)) - ), - @ApiResponse( - responseCode = "404", - description = "존재하지 않는 모임이거나 해당 모임 참여자가 아닌 경우", - content = @Content(schema = @Schema(implementation = ProblemDetail.class)) ) } ) @ErrorCode401 + @ErrorCode404(description = "존재하지 않는 약속이거나 해당 약속 참여자가 아닌 경우") @ErrorCode500 ResponseEntity findAllMateEtas( @Parameter(hidden = true) Member member, diff --git a/backend/src/main/java/com/ody/meeting/dto/request/MeetingSaveRequestV1.java b/backend/src/main/java/com/ody/meeting/dto/request/MeetingSaveRequestV1.java index 925276f4a..48339c498 100644 --- a/backend/src/main/java/com/ody/meeting/dto/request/MeetingSaveRequestV1.java +++ b/backend/src/main/java/com/ody/meeting/dto/request/MeetingSaveRequestV1.java @@ -1,6 +1,8 @@ package com.ody.meeting.dto.request; import com.ody.common.annotation.FutureOrPresentDateTime; +import com.ody.meeting.domain.Location; +import com.ody.meeting.domain.Meeting; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.Size; import java.time.LocalDate; @@ -29,4 +31,8 @@ public record MeetingSaveRequestV1( String targetLongitude ) { + public Meeting toMeeting(String inviteCode) { + Location target = new Location(targetAddress, targetLatitude, targetLongitude); + return new Meeting(name, date, time, target, inviteCode); + } } diff --git a/backend/src/main/java/com/ody/meeting/dto/response/MeetingSaveResponseV1.java b/backend/src/main/java/com/ody/meeting/dto/response/MeetingSaveResponseV1.java index 17e49a90c..154e41f08 100644 --- a/backend/src/main/java/com/ody/meeting/dto/response/MeetingSaveResponseV1.java +++ b/backend/src/main/java/com/ody/meeting/dto/response/MeetingSaveResponseV1.java @@ -1,5 +1,6 @@ package com.ody.meeting.dto.response; +import com.ody.meeting.domain.Meeting; import io.swagger.v3.oas.annotations.media.Schema; import java.time.LocalDate; import java.time.LocalTime; @@ -31,4 +32,16 @@ public record MeetingSaveResponseV1( String inviteCode ) { + public static MeetingSaveResponseV1 from(Meeting meeting) { + return new MeetingSaveResponseV1( + meeting.getId(), + meeting.getName(), + meeting.getDate(), + meeting.getTime().withNano(0), + meeting.getTarget().getAddress(), + meeting.getTarget().getLatitude(), + meeting.getTarget().getLongitude(), + meeting.getInviteCode() + ); + } } diff --git a/backend/src/main/java/com/ody/meeting/repository/MeetingRepository.java b/backend/src/main/java/com/ody/meeting/repository/MeetingRepository.java index 20a4b6ad6..ca7ebdaf1 100644 --- a/backend/src/main/java/com/ody/meeting/repository/MeetingRepository.java +++ b/backend/src/main/java/com/ody/meeting/repository/MeetingRepository.java @@ -3,7 +3,6 @@ import com.ody.meeting.domain.Meeting; import com.ody.member.domain.Member; import java.util.List; -import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; diff --git a/backend/src/main/java/com/ody/meeting/service/MeetingService.java b/backend/src/main/java/com/ody/meeting/service/MeetingService.java index d44dba955..04d72a2b5 100644 --- a/backend/src/main/java/com/ody/meeting/service/MeetingService.java +++ b/backend/src/main/java/com/ody/meeting/service/MeetingService.java @@ -10,8 +10,10 @@ import com.ody.meeting.domain.Meeting; import com.ody.meeting.dto.response.MateResponse; import com.ody.meeting.dto.request.MeetingSaveRequest; +import com.ody.meeting.dto.request.MeetingSaveRequestV1; import com.ody.meeting.dto.response.MeetingSaveResponse; import com.ody.meeting.dto.response.MeetingSaveResponses; +import com.ody.meeting.dto.response.MeetingSaveResponseV1; import com.ody.meeting.dto.response.MeetingWithMatesResponse; import com.ody.meeting.repository.MeetingRepository; import com.ody.member.domain.Member; @@ -41,6 +43,14 @@ public MeetingSaveResponse saveAndSendNotifications(MeetingSaveRequest meetingSa return mateService.saveAndSendNotifications(mateSaveRequest, meeting, member); } + @Transactional + public MeetingSaveResponseV1 saveV1(MeetingSaveRequestV1 meetingSaveRequestV1) { + Meeting meeting = meetingRepository.save(meetingSaveRequestV1.toMeeting(DEFAULT_INVITE_CODE)); + String encodedInviteCode = InviteCodeGenerator.encode(meeting.getId()); + meeting.updateInviteCode(encodedInviteCode); + return MeetingSaveResponseV1.from(meeting); + } + public Meeting save(MeetingSaveRequest meetingSaveRequest) { Meeting meeting = meetingRepository.save(meetingSaveRequest.toMeeting(DEFAULT_INVITE_CODE)); String encodedInviteCode = InviteCodeGenerator.encode(meeting.getId()); diff --git a/backend/src/main/java/com/ody/notification/repository/NotificationRepository.java b/backend/src/main/java/com/ody/notification/repository/NotificationRepository.java index 4fe0ab942..70a2e28bd 100644 --- a/backend/src/main/java/com/ody/notification/repository/NotificationRepository.java +++ b/backend/src/main/java/com/ody/notification/repository/NotificationRepository.java @@ -1,7 +1,6 @@ package com.ody.notification.repository; import com.ody.notification.domain.Notification; -import java.time.LocalDateTime; import java.util.List; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; diff --git a/backend/src/main/java/com/ody/route/mapper/OdsayResponseMapper.java b/backend/src/main/java/com/ody/route/mapper/OdsayResponseMapper.java index 9745bbf84..f5b6a9a11 100644 --- a/backend/src/main/java/com/ody/route/mapper/OdsayResponseMapper.java +++ b/backend/src/main/java/com/ody/route/mapper/OdsayResponseMapper.java @@ -26,7 +26,7 @@ public static long mapMinutes(OdsayResponse response) { return ZERO_TIME; } - if(response.code().isPresent()) { + if (response.code().isPresent()) { checkOdsayException(response); } @@ -49,7 +49,7 @@ private static void checkOdsayException(OdsayResponse response) { throw new OdyBadRequestException( response.message() - .orElse(EMPTY_MESSAGE) + .orElse(EMPTY_MESSAGE) ); } diff --git a/backend/src/main/java/com/ody/route/service/OdsayRouteClient.java b/backend/src/main/java/com/ody/route/service/OdsayRouteClient.java index 5b9595ba8..e5c51c595 100644 --- a/backend/src/main/java/com/ody/route/service/OdsayRouteClient.java +++ b/backend/src/main/java/com/ody/route/service/OdsayRouteClient.java @@ -37,7 +37,10 @@ private OdsayResponse getOdsayResponse(Location origin, Location target) { .uri(makeURI(origin, target)) .retrieve() .body(OdsayResponse.class); - return Objects.requireNonNullElseGet(response, () -> {throw new OdyServerErrorException("서버 에러");}); + return Objects.requireNonNullElseGet(response, () -> { + throw new OdyServerErrorException("서버 에러"); + } + ); } private URI makeURI(Location origin, Location target) { diff --git a/backend/src/test/java/com/ody/meeting/controller/MeetingControllerTest.java b/backend/src/test/java/com/ody/meeting/controller/MeetingControllerTest.java index 35b619a29..3321307b8 100644 --- a/backend/src/test/java/com/ody/meeting/controller/MeetingControllerTest.java +++ b/backend/src/test/java/com/ody/meeting/controller/MeetingControllerTest.java @@ -8,6 +8,7 @@ import com.ody.meeting.domain.Location; import com.ody.meeting.domain.Meeting; import com.ody.meeting.dto.request.MeetingSaveRequest; +import com.ody.meeting.dto.request.MeetingSaveRequestV1; import com.ody.meeting.repository.MeetingRepository; import com.ody.member.domain.DeviceToken; import com.ody.member.domain.Member; @@ -63,7 +64,32 @@ void save() { .when() .post("/meetings") .then() - .statusCode(HttpStatus.CREATED.value()); + .statusCode(201); + } + + @DisplayName("모임 개설 성공 시, 201을 응답한다") + @Test + void saveV1() { + String deviceToken = "Bearer device-token=testToken"; + memberService.save(new DeviceToken(deviceToken)); + + MeetingSaveRequestV1 meetingRequest = new MeetingSaveRequestV1( + "우테코 16조", + LocalDate.now().plusDays(1), + LocalTime.now().plusHours(1), + "서울 송파구 올림픽로35다길 42", + "37.515298", + "127.103113" + ); + + RestAssured.given().log().all() + .contentType(ContentType.JSON) + .header(HttpHeaders.AUTHORIZATION, deviceToken) + .body(meetingRequest) + .when() + .post("/v1/meetings") + .then() + .statusCode(201); } @DisplayName("특정 멤버의 참여 모임 목록 조회에 성공하면 200응답 반환한다") diff --git a/backend/src/test/java/com/ody/meeting/repository/MeetingRepositoryTest.java b/backend/src/test/java/com/ody/meeting/repository/MeetingRepositoryTest.java index 3215371cc..53b8ee3b9 100644 --- a/backend/src/test/java/com/ody/meeting/repository/MeetingRepositoryTest.java +++ b/backend/src/test/java/com/ody/meeting/repository/MeetingRepositoryTest.java @@ -11,7 +11,6 @@ import com.ody.member.domain.Member; import com.ody.member.repository.MemberRepository; import java.util.List; -import java.util.Optional; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; diff --git a/backend/src/test/java/com/ody/meeting/service/MeetingServiceTest.java b/backend/src/test/java/com/ody/meeting/service/MeetingServiceTest.java new file mode 100644 index 000000000..ba7f0da9a --- /dev/null +++ b/backend/src/test/java/com/ody/meeting/service/MeetingServiceTest.java @@ -0,0 +1,46 @@ +package com.ody.meeting.service; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; + +import com.ody.common.BaseServiceTest; +import com.ody.common.Fixture; +import com.ody.meeting.domain.Meeting; +import com.ody.meeting.dto.request.MeetingSaveRequestV1; +import com.ody.meeting.dto.response.MeetingSaveResponseV1; +import com.ody.util.InviteCodeGenerator; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; + +class MeetingServiceTest extends BaseServiceTest { + + @Autowired + MeetingService meetingService; + + @DisplayName("약속 저장 및 초대 코드 갱신에 성공한다") + @Test + void saveV1Success() { + Meeting testMeeting = Fixture.ODY_MEETING1; + MeetingSaveRequestV1 request = new MeetingSaveRequestV1( + testMeeting.getName(), + testMeeting.getDate(), + testMeeting.getTime(), + testMeeting.getTarget().getAddress(), + testMeeting.getTarget().getLatitude(), + testMeeting.getTarget().getLongitude() + ); + + MeetingSaveResponseV1 response = meetingService.saveV1(request); + + assertAll( + () -> assertThat(response.name()).isEqualTo(request.name()), + () -> assertThat(response.date()).isEqualTo(request.date()), + () -> assertThat(response.time()).isEqualTo(request.time()), + () -> assertThat(response.targetAddress()).isEqualTo(request.targetAddress()), + () -> assertThat(response.targetLatitude()).isEqualTo(request.targetLatitude()), + () -> assertThat(response.targetLongitude()).isEqualTo(request.targetLongitude()), + () -> assertThat(InviteCodeGenerator.decode(response.inviteCode())).isEqualTo(response.id()) + ); + } +}