From 84d7c07dc9f5e4122a75c85f31f686cf06d9b39b Mon Sep 17 00:00:00 2001 From: coli Date: Fri, 20 Mar 2026 02:44:05 +0900 Subject: [PATCH 01/15] =?UTF-8?q?feat:=20=ED=98=91=EC=9D=98=EB=90=9C=20?= =?UTF-8?q?=ED=98=95=EC=8B=9D=EC=97=90=20=EB=A7=9E=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=ED=98=95=EC=8B=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/sharing/SharingController.java | 8 ++- .../domain/sharing/TimerEventInfo.java | 16 ++++++ .../domain/sharing/TimerEventType.java | 12 +++++ .../dto/sharing/request/SharingRequest.java | 13 ++++- .../request/TimerEventInfoRequest.java | 24 +++++++++ .../dto/sharing/response/SharingResponse.java | 13 ++++- .../response/TimerEventInfoResponse.java | 25 +++++++++ .../sharing/SharingControllerTest.java | 54 +++++++++++++++++-- 8 files changed, 152 insertions(+), 13 deletions(-) create mode 100644 src/main/java/com/debatetimer/domain/sharing/TimerEventInfo.java create mode 100644 src/main/java/com/debatetimer/domain/sharing/TimerEventType.java create mode 100644 src/main/java/com/debatetimer/dto/sharing/request/TimerEventInfoRequest.java create mode 100644 src/main/java/com/debatetimer/dto/sharing/response/TimerEventInfoResponse.java diff --git a/src/main/java/com/debatetimer/controller/sharing/SharingController.java b/src/main/java/com/debatetimer/controller/sharing/SharingController.java index edacf8e6..474248f7 100644 --- a/src/main/java/com/debatetimer/controller/sharing/SharingController.java +++ b/src/main/java/com/debatetimer/controller/sharing/SharingController.java @@ -1,9 +1,8 @@ package com.debatetimer.controller.sharing; -import com.debatetimer.controller.auth.AuthMember; -import com.debatetimer.domain.member.Member; import com.debatetimer.dto.sharing.request.SharingRequest; import com.debatetimer.dto.sharing.response.SharingResponse; +import jakarta.validation.Valid; import org.springframework.messaging.handler.annotation.DestinationVariable; import org.springframework.messaging.handler.annotation.MessageMapping; import org.springframework.messaging.handler.annotation.Payload; @@ -16,10 +15,9 @@ public class SharingController { @MessageMapping("/event/{roomId}") @SendTo("/room/{roomId}") public SharingResponse share( - @AuthMember Member member, @DestinationVariable(value = "roomId") long roomId, - @Payload SharingRequest request + @Valid @Payload SharingRequest request ) { - return new SharingResponse(request.time()); + return new SharingResponse(request.eventType(), request.toTimerEventInfo()); } } diff --git a/src/main/java/com/debatetimer/domain/sharing/TimerEventInfo.java b/src/main/java/com/debatetimer/domain/sharing/TimerEventInfo.java new file mode 100644 index 00000000..1aa9183e --- /dev/null +++ b/src/main/java/com/debatetimer/domain/sharing/TimerEventInfo.java @@ -0,0 +1,16 @@ +package com.debatetimer.domain.sharing; + +import com.debatetimer.domain.customize.CustomizeBoxType; +import com.debatetimer.domain.customize.Stance; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public class TimerEventInfo { + + private final CustomizeBoxType timerType; + private final int sequence; + private final Stance currentTeam; + private final long remainingTime; +} diff --git a/src/main/java/com/debatetimer/domain/sharing/TimerEventType.java b/src/main/java/com/debatetimer/domain/sharing/TimerEventType.java new file mode 100644 index 00000000..33e1c5dd --- /dev/null +++ b/src/main/java/com/debatetimer/domain/sharing/TimerEventType.java @@ -0,0 +1,12 @@ +package com.debatetimer.domain.sharing; + +public enum TimerEventType { + + NEXT, + BEFORE, + STOP, + PLAY, + RESET, + TEAM_SWITCH, + FINISHED +} diff --git a/src/main/java/com/debatetimer/dto/sharing/request/SharingRequest.java b/src/main/java/com/debatetimer/dto/sharing/request/SharingRequest.java index b6063711..cbb3ffc8 100644 --- a/src/main/java/com/debatetimer/dto/sharing/request/SharingRequest.java +++ b/src/main/java/com/debatetimer/dto/sharing/request/SharingRequest.java @@ -1,9 +1,18 @@ package com.debatetimer.dto.sharing.request; -import java.time.LocalDateTime; +import com.debatetimer.domain.sharing.TimerEventInfo; +import com.debatetimer.domain.sharing.TimerEventType; +import jakarta.validation.Valid; public record SharingRequest( - LocalDateTime time + TimerEventType eventType, + @Valid TimerEventInfoRequest data ) { + public TimerEventInfo toTimerEventInfo() { + if (data == null) { + return null; + } + return data.toTimerEventInfo(); + } } diff --git a/src/main/java/com/debatetimer/dto/sharing/request/TimerEventInfoRequest.java b/src/main/java/com/debatetimer/dto/sharing/request/TimerEventInfoRequest.java new file mode 100644 index 00000000..0485a56c --- /dev/null +++ b/src/main/java/com/debatetimer/dto/sharing/request/TimerEventInfoRequest.java @@ -0,0 +1,24 @@ +package com.debatetimer.dto.sharing.request; + +import com.debatetimer.domain.customize.CustomizeBoxType; +import com.debatetimer.domain.customize.Stance; +import com.debatetimer.domain.sharing.TimerEventInfo; +import jakarta.annotation.Nullable; +import jakarta.validation.constraints.NotNull; + +public record TimerEventInfoRequest( + @NotNull CustomizeBoxType timerType, + int sequence, + @Nullable Stance currentTeam, + long time +) { + + public TimerEventInfo toTimerEventInfo() { + return new TimerEventInfo( + timerType, + sequence, + currentTeam, + time + ); + } +} diff --git a/src/main/java/com/debatetimer/dto/sharing/response/SharingResponse.java b/src/main/java/com/debatetimer/dto/sharing/response/SharingResponse.java index 704384d1..bf68da29 100644 --- a/src/main/java/com/debatetimer/dto/sharing/response/SharingResponse.java +++ b/src/main/java/com/debatetimer/dto/sharing/response/SharingResponse.java @@ -1,9 +1,18 @@ package com.debatetimer.dto.sharing.response; -import java.time.LocalDateTime; +import com.debatetimer.domain.sharing.TimerEventInfo; +import com.debatetimer.domain.sharing.TimerEventType; public record SharingResponse( - LocalDateTime time + TimerEventType eventType, + TimerEventInfoResponse data ) { + public SharingResponse(TimerEventType eventType, TimerEventInfo timerEventInfo) { + this( + eventType, + new TimerEventInfoResponse(timerEventInfo) + ); + } + } diff --git a/src/main/java/com/debatetimer/dto/sharing/response/TimerEventInfoResponse.java b/src/main/java/com/debatetimer/dto/sharing/response/TimerEventInfoResponse.java new file mode 100644 index 00000000..af97fc3b --- /dev/null +++ b/src/main/java/com/debatetimer/dto/sharing/response/TimerEventInfoResponse.java @@ -0,0 +1,25 @@ +package com.debatetimer.dto.sharing.response; + + +import com.debatetimer.domain.customize.CustomizeBoxType; +import com.debatetimer.domain.customize.Stance; +import com.debatetimer.domain.sharing.TimerEventInfo; +import jakarta.annotation.Nullable; +import jakarta.validation.constraints.NotNull; + +public record TimerEventInfoResponse( + @NotNull CustomizeBoxType timerType, + int sequence, + @Nullable Stance currentTeam, + long time +) { + + public TimerEventInfoResponse(TimerEventInfo timerEventInfo) { + this( + timerEventInfo.getTimerType(), + timerEventInfo.getSequence(), + timerEventInfo.getCurrentTeam(), + timerEventInfo.getRemainingTime() + ); + } +} diff --git a/src/test/java/com/debatetimer/controller/sharing/SharingControllerTest.java b/src/test/java/com/debatetimer/controller/sharing/SharingControllerTest.java index c1362bc5..4ce39c16 100644 --- a/src/test/java/com/debatetimer/controller/sharing/SharingControllerTest.java +++ b/src/test/java/com/debatetimer/controller/sharing/SharingControllerTest.java @@ -1,18 +1,24 @@ package com.debatetimer.controller.sharing; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertAll; import com.debatetimer.BaseStompTest; import com.debatetimer.MessageFrameHandler; +import com.debatetimer.domain.customize.CustomizeBoxType; import com.debatetimer.domain.member.Member; +import com.debatetimer.domain.sharing.TimerEventType; import com.debatetimer.dto.sharing.request.SharingRequest; +import com.debatetimer.dto.sharing.request.TimerEventInfoRequest; import com.debatetimer.dto.sharing.response.SharingResponse; -import java.time.LocalDateTime; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.NullSource; import org.springframework.messaging.simp.stomp.StompHeaders; class SharingControllerTest extends BaseStompTest { @@ -23,17 +29,57 @@ class Share { @Test void 사회자가_발생시킨_이벤트를_청중이_공유받는다() throws ExecutionException, InterruptedException, TimeoutException { long roomId = 1L; - LocalDateTime time = LocalDateTime.now(); MessageFrameHandler handler = new MessageFrameHandler<>(SharingResponse.class); Member member = memberGenerator.generate("example@email.com"); StompHeaders headers = headerGenerator.generateAccessTokenHeader("/app/event/" + roomId, member); + SharingRequest request = new SharingRequest( + TimerEventType.NEXT, + new TimerEventInfoRequest( + CustomizeBoxType.NORMAL, + 2, + null, + 30 + ) + ); stompSession.subscribe("/room/" + roomId, handler); //청중의 구독 - stompSession.send(headers, new SharingRequest(time)); //사회자의 이벤트 발생 + stompSession.send(headers, request); //사회자의 이벤트 발생 SharingResponse response = handler.getCompletableFuture() .get(3L, TimeUnit.SECONDS); - assertThat(response.time()).isEqualTo(time); + + assertAll( + () -> assertThat(response.eventType()).isEqualTo(request.eventType()), + () -> assertThat(response.data().timerType()).isEqualTo(request.data().timerType()), + () -> assertThat(response.data().sequence()).isEqualTo(request.data().sequence()), + () -> assertThat(response.data().currentTeam()).isEqualTo(request.data().currentTeam()), + () -> assertThat(response.data().time()).isEqualTo(request.data().time()) + ); + } + + @ParameterizedTest + @NullSource + void 타이머_타입은_빈_값일_수_없다(CustomizeBoxType boxType) { + long roomId = 1L; + MessageFrameHandler handler = new MessageFrameHandler<>(SharingResponse.class); + Member member = memberGenerator.generate("example@email.com"); + StompHeaders headers = headerGenerator.generateAccessTokenHeader("/app/event/" + roomId, member); + SharingRequest request = new SharingRequest( + TimerEventType.NEXT, + new TimerEventInfoRequest( + boxType, + 2, + null, + 30 + ) + ); + stompSession.subscribe("/room/" + roomId, handler); //청중의 구독 + + stompSession.send(headers, request); //사회자의 이벤트 발생 + + assertThatThrownBy(() -> handler.getCompletableFuture() + .get(2L, TimeUnit.SECONDS)) + .isInstanceOf(TimeoutException.class); } } } From d30f7de9180b393215116288747b4654f59d1fcd Mon Sep 17 00:00:00 2001 From: coli Date: Fri, 20 Mar 2026 02:45:50 +0900 Subject: [PATCH 02/15] =?UTF-8?q?fix:=20=EC=A0=84=ED=9B=84=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C=20=EB=A1=9C=EC=A7=81=EC=9D=84=20StompTest=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95=EC=97=90=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/com/debatetimer/BaseStompTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/test/java/com/debatetimer/BaseStompTest.java b/src/test/java/com/debatetimer/BaseStompTest.java index 4f0410c0..cf38a6e4 100644 --- a/src/test/java/com/debatetimer/BaseStompTest.java +++ b/src/test/java/com/debatetimer/BaseStompTest.java @@ -10,6 +10,7 @@ import java.util.concurrent.TimeoutException; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.web.server.LocalServerPort; @@ -23,6 +24,7 @@ import org.springframework.web.socket.sockjs.client.Transport; import org.springframework.web.socket.sockjs.client.WebSocketTransport; +@ExtendWith(DataBaseCleaner.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) public abstract class BaseStompTest { From e82a65efa5e63561c3255f44958e91b6e71109fd Mon Sep 17 00:00:00 2001 From: coli Date: Wed, 25 Mar 2026 00:29:18 +0900 Subject: [PATCH 03/15] =?UTF-8?q?feat:=20nullable=20=ED=91=9C=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/debatetimer/domain/sharing/TimerEventInfo.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/com/debatetimer/domain/sharing/TimerEventInfo.java b/src/main/java/com/debatetimer/domain/sharing/TimerEventInfo.java index 1aa9183e..741f9212 100644 --- a/src/main/java/com/debatetimer/domain/sharing/TimerEventInfo.java +++ b/src/main/java/com/debatetimer/domain/sharing/TimerEventInfo.java @@ -2,6 +2,8 @@ import com.debatetimer.domain.customize.CustomizeBoxType; import com.debatetimer.domain.customize.Stance; +import jakarta.annotation.Nullable; +import jakarta.validation.constraints.NotNull; import lombok.Getter; import lombok.RequiredArgsConstructor; @@ -9,8 +11,13 @@ @RequiredArgsConstructor public class TimerEventInfo { + @NotNull private final CustomizeBoxType timerType; + private final int sequence; + + @Nullable private final Stance currentTeam; + private final long remainingTime; } From c955a7fd67ea0aa27bac2dac2a9d4665ba44a642 Mon Sep 17 00:00:00 2001 From: coli Date: Wed, 25 Mar 2026 00:47:37 +0900 Subject: [PATCH 04/15] =?UTF-8?q?feat:=20Optional=EC=9D=84=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=ED=95=98=EB=8A=94=20=EB=B0=A9=EC=8B=9D=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/sharing/request/SharingRequest.java | 15 +++++++++------ .../dto/sharing/response/SharingResponse.java | 14 +++++++++++--- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/debatetimer/dto/sharing/request/SharingRequest.java b/src/main/java/com/debatetimer/dto/sharing/request/SharingRequest.java index cbb3ffc8..16da06d9 100644 --- a/src/main/java/com/debatetimer/dto/sharing/request/SharingRequest.java +++ b/src/main/java/com/debatetimer/dto/sharing/request/SharingRequest.java @@ -2,17 +2,20 @@ import com.debatetimer.domain.sharing.TimerEventInfo; import com.debatetimer.domain.sharing.TimerEventType; +import jakarta.annotation.Nullable; import jakarta.validation.Valid; +import java.util.Optional; public record SharingRequest( TimerEventType eventType, - @Valid TimerEventInfoRequest data + + @Valid + @Nullable + TimerEventInfoRequest data ) { - public TimerEventInfo toTimerEventInfo() { - if (data == null) { - return null; - } - return data.toTimerEventInfo(); + public Optional toTimerEventInfo() { + return Optional.ofNullable(data) + .map(TimerEventInfoRequest::toTimerEventInfo); } } diff --git a/src/main/java/com/debatetimer/dto/sharing/response/SharingResponse.java b/src/main/java/com/debatetimer/dto/sharing/response/SharingResponse.java index bf68da29..23dd6348 100644 --- a/src/main/java/com/debatetimer/dto/sharing/response/SharingResponse.java +++ b/src/main/java/com/debatetimer/dto/sharing/response/SharingResponse.java @@ -2,17 +2,25 @@ import com.debatetimer.domain.sharing.TimerEventInfo; import com.debatetimer.domain.sharing.TimerEventType; +import jakarta.annotation.Nullable; +import java.util.Optional; public record SharingResponse( TimerEventType eventType, + + @Nullable TimerEventInfoResponse data ) { - public SharingResponse(TimerEventType eventType, TimerEventInfo timerEventInfo) { + public SharingResponse( + TimerEventType eventType, + Optional timerEventInfo + ) { this( eventType, - new TimerEventInfoResponse(timerEventInfo) + timerEventInfo + .map(TimerEventInfoResponse::new) + .orElse(null) ); } - } From d7593533287f09efbb45c404e201e5cba88f1889 Mon Sep 17 00:00:00 2001 From: coli Date: Wed, 25 Mar 2026 01:04:34 +0900 Subject: [PATCH 05/15] =?UTF-8?q?feat:=20Nullable=20=EC=95=A0=EB=84=88?= =?UTF-8?q?=ED=85=8C=EC=9D=B4=EC=85=98=20=ED=91=9C=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/sharing/SharingController.java | 10 +++++++- .../dto/sharing/request/SharingRequest.java | 9 ++++++-- .../dto/sharing/response/SharingResponse.java | 13 ----------- .../sharing/SharingControllerTest.java | 23 +++++++++++++++++++ 4 files changed, 39 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/debatetimer/controller/sharing/SharingController.java b/src/main/java/com/debatetimer/controller/sharing/SharingController.java index 474248f7..8a8d9ccd 100644 --- a/src/main/java/com/debatetimer/controller/sharing/SharingController.java +++ b/src/main/java/com/debatetimer/controller/sharing/SharingController.java @@ -2,6 +2,7 @@ import com.debatetimer.dto.sharing.request.SharingRequest; import com.debatetimer.dto.sharing.response.SharingResponse; +import com.debatetimer.dto.sharing.response.TimerEventInfoResponse; import jakarta.validation.Valid; import org.springframework.messaging.handler.annotation.DestinationVariable; import org.springframework.messaging.handler.annotation.MessageMapping; @@ -18,6 +19,13 @@ public SharingResponse share( @DestinationVariable(value = "roomId") long roomId, @Valid @Payload SharingRequest request ) { - return new SharingResponse(request.eventType(), request.toTimerEventInfo()); + if (!request.hasEvent()) { + return new SharingResponse(request.eventType(), null); + } + + return new SharingResponse( + request.eventType(), + new TimerEventInfoResponse(request.toTimerEventInfo()) + ); } } diff --git a/src/main/java/com/debatetimer/dto/sharing/request/SharingRequest.java b/src/main/java/com/debatetimer/dto/sharing/request/SharingRequest.java index 16da06d9..ec86e573 100644 --- a/src/main/java/com/debatetimer/dto/sharing/request/SharingRequest.java +++ b/src/main/java/com/debatetimer/dto/sharing/request/SharingRequest.java @@ -14,8 +14,13 @@ public record SharingRequest( TimerEventInfoRequest data ) { - public Optional toTimerEventInfo() { + public boolean hasEvent() { + return eventType != null; + } + + public TimerEventInfo toTimerEventInfo() { return Optional.ofNullable(data) - .map(TimerEventInfoRequest::toTimerEventInfo); + .map(TimerEventInfoRequest::toTimerEventInfo) + .orElse(null); } } diff --git a/src/main/java/com/debatetimer/dto/sharing/response/SharingResponse.java b/src/main/java/com/debatetimer/dto/sharing/response/SharingResponse.java index 23dd6348..71a2d43e 100644 --- a/src/main/java/com/debatetimer/dto/sharing/response/SharingResponse.java +++ b/src/main/java/com/debatetimer/dto/sharing/response/SharingResponse.java @@ -1,9 +1,7 @@ package com.debatetimer.dto.sharing.response; -import com.debatetimer.domain.sharing.TimerEventInfo; import com.debatetimer.domain.sharing.TimerEventType; import jakarta.annotation.Nullable; -import java.util.Optional; public record SharingResponse( TimerEventType eventType, @@ -12,15 +10,4 @@ public record SharingResponse( TimerEventInfoResponse data ) { - public SharingResponse( - TimerEventType eventType, - Optional timerEventInfo - ) { - this( - eventType, - timerEventInfo - .map(TimerEventInfoResponse::new) - .orElse(null) - ); - } } diff --git a/src/test/java/com/debatetimer/controller/sharing/SharingControllerTest.java b/src/test/java/com/debatetimer/controller/sharing/SharingControllerTest.java index 4ce39c16..5e4ab59e 100644 --- a/src/test/java/com/debatetimer/controller/sharing/SharingControllerTest.java +++ b/src/test/java/com/debatetimer/controller/sharing/SharingControllerTest.java @@ -57,6 +57,29 @@ class Share { ); } + @Test + void 사회자가_발생시킨_토론_종료_이벤트를_청중이_공유받는다() throws ExecutionException, InterruptedException, TimeoutException { + long roomId = 1L; + MessageFrameHandler handler = new MessageFrameHandler<>(SharingResponse.class); + Member member = memberGenerator.generate("example@email.com"); + StompHeaders headers = headerGenerator.generateAccessTokenHeader("/app/event/" + roomId, member); + SharingRequest request = new SharingRequest(TimerEventType.FINISHED, null); + stompSession.subscribe("/room/" + roomId, handler); //청중의 구독 + + stompSession.send(headers, request); //사회자의 이벤트 발생 + + SharingResponse response = handler.getCompletableFuture() + .get(3L, TimeUnit.SECONDS); + + assertAll( + () -> assertThat(response.eventType()).isEqualTo(request.eventType()), + () -> assertThat(response.data().timerType()).isEqualTo(request.data().timerType()), + () -> assertThat(response.data().sequence()).isEqualTo(request.data().sequence()), + () -> assertThat(response.data().currentTeam()).isEqualTo(request.data().currentTeam()), + () -> assertThat(response.data().time()).isEqualTo(request.data().time()) + ); + } + @ParameterizedTest @NullSource void 타이머_타입은_빈_값일_수_없다(CustomizeBoxType boxType) { From d37b99dd5c218fcba4cb4cbb8af5b924927f9787 Mon Sep 17 00:00:00 2001 From: coli Date: Wed, 25 Mar 2026 01:07:24 +0900 Subject: [PATCH 06/15] rename: time > remainingTime --- .../request/TimerEventInfoRequest.java | 4 +- .../response/TimerEventInfoResponse.java | 2 +- .../controller/BaseControllerTest.java | 4 +- .../customize/CustomizeDocumentTest.java | 64 +++++++++++-------- .../sharing/SharingControllerTest.java | 4 +- 5 files changed, 43 insertions(+), 35 deletions(-) diff --git a/src/main/java/com/debatetimer/dto/sharing/request/TimerEventInfoRequest.java b/src/main/java/com/debatetimer/dto/sharing/request/TimerEventInfoRequest.java index 0485a56c..1cf85ae4 100644 --- a/src/main/java/com/debatetimer/dto/sharing/request/TimerEventInfoRequest.java +++ b/src/main/java/com/debatetimer/dto/sharing/request/TimerEventInfoRequest.java @@ -10,7 +10,7 @@ public record TimerEventInfoRequest( @NotNull CustomizeBoxType timerType, int sequence, @Nullable Stance currentTeam, - long time + long remainingTime ) { public TimerEventInfo toTimerEventInfo() { @@ -18,7 +18,7 @@ public TimerEventInfo toTimerEventInfo() { timerType, sequence, currentTeam, - time + remainingTime ); } } diff --git a/src/main/java/com/debatetimer/dto/sharing/response/TimerEventInfoResponse.java b/src/main/java/com/debatetimer/dto/sharing/response/TimerEventInfoResponse.java index af97fc3b..617bda80 100644 --- a/src/main/java/com/debatetimer/dto/sharing/response/TimerEventInfoResponse.java +++ b/src/main/java/com/debatetimer/dto/sharing/response/TimerEventInfoResponse.java @@ -11,7 +11,7 @@ public record TimerEventInfoResponse( @NotNull CustomizeBoxType timerType, int sequence, @Nullable Stance currentTeam, - long time + long remainingTime ) { public TimerEventInfoResponse(TimerEventInfo timerEventInfo) { diff --git a/src/test/java/com/debatetimer/controller/BaseControllerTest.java b/src/test/java/com/debatetimer/controller/BaseControllerTest.java index 2c43b995..ab03fbaa 100644 --- a/src/test/java/com/debatetimer/controller/BaseControllerTest.java +++ b/src/test/java/com/debatetimer/controller/BaseControllerTest.java @@ -124,7 +124,7 @@ private ArbitraryBuilder getCustomizeTimeBoxCreat .set("stance", Stance.PROS) .set("speechType", "입론1") .set("boxType", CustomizeBoxType.NORMAL) - .set("time", 120) + .set("remainingTime", 120) .set("bell", getBellRequestBuilder().sampleList(2)) .set("timePerTeam", 60) .set("timePerSpeaking", null) @@ -134,7 +134,7 @@ private ArbitraryBuilder getCustomizeTimeBoxCreat private ArbitraryBuilder getBellRequestBuilder() { return fixtureMonkey.giveMeBuilder(BellRequest.class) .set("type", BellType.AFTER_START) - .set("time", 30) + .set("remainingTime", 30) .set("count", 1); } } diff --git a/src/test/java/com/debatetimer/controller/customize/CustomizeDocumentTest.java b/src/test/java/com/debatetimer/controller/customize/CustomizeDocumentTest.java index e2613aa0..113144e0 100644 --- a/src/test/java/com/debatetimer/controller/customize/CustomizeDocumentTest.java +++ b/src/test/java/com/debatetimer/controller/customize/CustomizeDocumentTest.java @@ -52,8 +52,8 @@ class Save { ### 타임 박스 종류에 따른 요청 값 | 타임 박스 종류 | 필수 입력 | 선택 입력 | null 입력 | | :---: | ---| --- | --- | - | 커스텀 타임 박스 | stance, speechType, boxType, time | speaker | timePerTeam, timePerSpeaking | - | 자유 토론 타임 박스 | stance, speechType, boxType, timePerTeam | speaker, timePerSpeaking | time | + | 커스텀 타임 박스 | stance, speechType, boxType, remainingTime | speaker | timePerTeam, timePerSpeaking | + | 자유 토론 타임 박스 | stance, speechType, boxType, timePerTeam | speaker, timePerSpeaking | remainingTime | """) .requestHeader( headerWithName(HttpHeaders.AUTHORIZATION).description("액세스 토큰") @@ -70,10 +70,10 @@ class Save { fieldWithPath("table[].stance").type(STRING).description("입장"), fieldWithPath("table[].speechType").type(STRING).description("발언 유형"), fieldWithPath("table[].boxType").type(STRING).description("타임 박스 유형"), - fieldWithPath("table[].time").type(NUMBER).description("발언 시간(초)").optional(), + fieldWithPath("table[].remainingTime").type(NUMBER).description("발언 시간(초)").optional(), fieldWithPath("table[].bell").type(ARRAY).description("종소리 정보").optional(), fieldWithPath("table[].bell[].type").type(STRING).description("종소리 종류"), - fieldWithPath("table[].bell[].time").type(NUMBER).description("종소리 울릴 시간(초)"), + fieldWithPath("table[].bell[].remainingTime").type(NUMBER).description("종소리 울릴 시간(초)"), fieldWithPath("table[].bell[].count").type(NUMBER).description("종소리 횟수"), fieldWithPath("table[].timePerTeam").type(NUMBER).description("팀당 발언 시간 (초)").optional(), fieldWithPath("table[].timePerSpeaking").type(NUMBER).description("1회 발언 시간 (초)").optional(), @@ -95,10 +95,10 @@ class Save { fieldWithPath("table[].stance").type(STRING).description("입장"), fieldWithPath("table[].speechType").type(STRING).description("발언 유형"), fieldWithPath("table[].boxType").type(STRING).description("타임 박스 유형"), - fieldWithPath("table[].time").type(NUMBER).description("발언 시간(초)").optional(), + fieldWithPath("table[].remainingTime").type(NUMBER).description("발언 시간(초)").optional(), fieldWithPath("table[].bell").type(ARRAY).description("종소리 정보").optional(), fieldWithPath("table[].bell[].type").type(STRING).description("종소리 종류"), - fieldWithPath("table[].bell[].time").type(NUMBER).description("종소리 울릴 시간(초)"), + fieldWithPath("table[].bell[].remainingTime").type(NUMBER).description("종소리 울릴 시간(초)"), fieldWithPath("table[].bell[].count").type(NUMBER).description("종소리 횟수"), fieldWithPath("table[].timePerTeam").type(NUMBER).description("팀당 발언 시간 (초)").optional(), fieldWithPath("table[].timePerSpeaking").type(NUMBER).description("1회 발언 시간 (초)").optional(), @@ -114,7 +114,8 @@ class Save { new CustomizeTimeBoxCreateRequest(Stance.PROS, "입론", CustomizeBoxType.NORMAL, 120, List.of(new BellRequest(BellType.AFTER_START, 90, 1)), null, null, "콜리"), new CustomizeTimeBoxCreateRequest(Stance.CONS, "입론", CustomizeBoxType.NORMAL, - 120, List.of(new BellRequest(BellType.AFTER_START, 90, 1), new BellRequest(BellType.AFTER_START, 120, 2)), null, null, "비토"), + 120, List.of(new BellRequest(BellType.AFTER_START, 90, 1), + new BellRequest(BellType.AFTER_START, 120, 2)), null, null, "비토"), new CustomizeTimeBoxCreateRequest(Stance.NEUTRAL, "난상 토론", CustomizeBoxType.TIME_BASED, null, null, 360, 120, null), new CustomizeTimeBoxCreateRequest(Stance.NEUTRAL, "존중 토론", CustomizeBoxType.TIME_BASED, @@ -129,7 +130,8 @@ class Save { new CustomizeTimeBoxResponse(Stance.PROS, "입론", CustomizeBoxType.NORMAL, 120, List.of(new BellResponse(BellType.AFTER_START, 90, 1)), null, null, "콜리"), new CustomizeTimeBoxResponse(Stance.CONS, "입론", CustomizeBoxType.NORMAL, - 120, List.of(new BellResponse(BellType.AFTER_START, 90, 1), new BellResponse(BellType.AFTER_START, 120, 2)), null, null, "비토"), + 120, List.of(new BellResponse(BellType.AFTER_START, 90, 1), + new BellResponse(BellType.AFTER_START, 120, 2)), null, null, "비토"), new CustomizeTimeBoxResponse(Stance.NEUTRAL, "난상 토론", CustomizeBoxType.TIME_BASED, null, null, 360, 120, null), new CustomizeTimeBoxResponse(Stance.NEUTRAL, "존중 토론", CustomizeBoxType.TIME_BASED, @@ -173,7 +175,8 @@ class Save { new CustomizeTimeBoxCreateRequest(Stance.PROS, "입론", CustomizeBoxType.NORMAL, 120, List.of(new BellRequest(BellType.AFTER_START, 90, 1)), null, null, "콜리"), new CustomizeTimeBoxCreateRequest(Stance.CONS, "입론", CustomizeBoxType.NORMAL, - 120, List.of(new BellRequest(BellType.AFTER_START, 90, 1), new BellRequest(BellType.AFTER_START, 120, 2)), null, null, "비토"), + 120, List.of(new BellRequest(BellType.AFTER_START, 90, 1), + new BellRequest(BellType.AFTER_START, 120, 2)), null, null, "비토"), new CustomizeTimeBoxCreateRequest(Stance.NEUTRAL, "난상 토론", CustomizeBoxType.TIME_BASED, null, null, 360, 120, null), new CustomizeTimeBoxCreateRequest(Stance.NEUTRAL, "존중 토론", CustomizeBoxType.TIME_BASED, @@ -205,8 +208,8 @@ class GetTable { ### 타임 박스 종류에 따른 웅답 값 | 타임 박스 종류 | 필수 입력 | 선택 입력 | null 입력 | | :---: | ---| --- | --- | - | 커스텀 타임 박스 | stance, speechType, boxType, time | speaker | timePerTeam, timePerSpeaking | - | 자유 토론 타임 박스 | stance, speechType, boxType, timePerTeam | speaker, timePerSpeaking | time | + | 커스텀 타임 박스 | stance, speechType, boxType, remainingTime | speaker | timePerTeam, timePerSpeaking | + | 자유 토론 타임 박스 | stance, speechType, boxType, timePerTeam | speaker, timePerSpeaking | remainingTime | """) .tag(Tag.CUSTOMIZE_API) .requestHeader( @@ -231,10 +234,10 @@ class GetTable { fieldWithPath("table[].stance").type(STRING).description("입장"), fieldWithPath("table[].speechType").type(STRING).description("발언 유형"), fieldWithPath("table[].boxType").type(STRING).description("타임 박스 유형"), - fieldWithPath("table[].time").type(NUMBER).description("발언 시간(초)").optional(), + fieldWithPath("table[].remainingTime").type(NUMBER).description("발언 시간(초)").optional(), fieldWithPath("table[].bell").type(ARRAY).description("종소리 정보").optional(), fieldWithPath("table[].bell[].type").type(STRING).description("종소리 종류"), - fieldWithPath("table[].bell[].time").type(NUMBER).description("종소리 울릴 시간(초)"), + fieldWithPath("table[].bell[].remainingTime").type(NUMBER).description("종소리 울릴 시간(초)"), fieldWithPath("table[].bell[].count").type(NUMBER).description("종소리 횟수"), fieldWithPath("table[].timePerTeam").type(NUMBER).description("팀당 발언 시간 (초)").optional(), fieldWithPath("table[].timePerSpeaking").type(NUMBER).description("1회 발언 시간 (초)").optional(), @@ -252,7 +255,8 @@ class GetTable { new CustomizeTimeBoxResponse(Stance.PROS, "입론", CustomizeBoxType.NORMAL, 120, List.of(new BellResponse(BellType.AFTER_START, 90, 1)), null, null, "콜리"), new CustomizeTimeBoxResponse(Stance.CONS, "입론", CustomizeBoxType.NORMAL, - 120, List.of(new BellResponse(BellType.AFTER_START, 90, 1), new BellResponse(BellType.AFTER_START, 120, 2)), null, null, "비토"), + 120, List.of(new BellResponse(BellType.AFTER_START, 90, 1), + new BellResponse(BellType.AFTER_START, 120, 2)), null, null, "비토"), new CustomizeTimeBoxResponse(Stance.NEUTRAL, "난상 토론", CustomizeBoxType.TIME_BASED, null, null, 360, 120, null), new CustomizeTimeBoxResponse(Stance.NEUTRAL, "존중 토론", CustomizeBoxType.TIME_BASED, @@ -304,8 +308,8 @@ class UpdateTable { ### 타임 박스 종류에 따른 요청/웅답 값 | 타임 박스 종류 | 필수 입력 | 선택 입력 | null 입력 | | :---: | ---| --- | --- | - | 커스텀 타임 박스 | stance, speechType, boxType, time | speaker | timePerTeam, timePerSpeaking | - | 자유 토론 타임 박스 | stance, speechType, boxType, timePerTeam | speaker, timePerSpeaking | time | + | 커스텀 타임 박스 | stance, speechType, boxType, remainingTime | speaker | timePerTeam, timePerSpeaking | + | 자유 토론 타임 박스 | stance, speechType, boxType, timePerTeam | speaker, timePerSpeaking | remainingTime | """) .requestHeader( headerWithName(HttpHeaders.AUTHORIZATION).description("액세스 토큰") @@ -325,10 +329,10 @@ class UpdateTable { fieldWithPath("table[].stance").type(STRING).description("입장"), fieldWithPath("table[].speechType").type(STRING).description("발언 유형"), fieldWithPath("table[].boxType").type(STRING).description("타임 박스 유형"), - fieldWithPath("table[].time").type(NUMBER).description("발언 시간(초)").optional(), + fieldWithPath("table[].remainingTime").type(NUMBER).description("발언 시간(초)").optional(), fieldWithPath("table[].bell").type(ARRAY).description("종소리 정보").optional(), fieldWithPath("table[].bell[].type").type(STRING).description("종소리 종류"), - fieldWithPath("table[].bell[].time").type(NUMBER).description("종소리 울릴 시간(초)"), + fieldWithPath("table[].bell[].remainingTime").type(NUMBER).description("종소리 울릴 시간(초)"), fieldWithPath("table[].bell[].count").type(NUMBER).description("종소리 횟수"), fieldWithPath("table[].timePerTeam").type(NUMBER).description("팀당 발언 시간 (초)").optional(), fieldWithPath("table[].timePerSpeaking").type(NUMBER).description("1회 발언 시간 (초)").optional(), @@ -350,10 +354,10 @@ class UpdateTable { fieldWithPath("table[].stance").type(STRING).description("입장"), fieldWithPath("table[].speechType").type(STRING).description("발언 유형"), fieldWithPath("table[].boxType").type(STRING).description("타임 박스 유형"), - fieldWithPath("table[].time").type(NUMBER).description("발언 시간(초)").optional(), + fieldWithPath("table[].remainingTime").type(NUMBER).description("발언 시간(초)").optional(), fieldWithPath("table[].bell").type(ARRAY).description("종소리 정보").optional(), fieldWithPath("table[].bell[].type").type(STRING).description("종소리 종류"), - fieldWithPath("table[].bell[].time").type(NUMBER).description("종소리 울릴 시간(초)"), + fieldWithPath("table[].bell[].remainingTime").type(NUMBER).description("종소리 울릴 시간(초)"), fieldWithPath("table[].bell[].count").type(NUMBER).description("종소리 횟수"), fieldWithPath("table[].timePerTeam").type(NUMBER).description("팀당 발언 시간 (초)").optional(), fieldWithPath("table[].timePerSpeaking").type(NUMBER).description("1회 발언 시간 (초)").optional(), @@ -370,7 +374,8 @@ class UpdateTable { new CustomizeTimeBoxCreateRequest(Stance.PROS, "입론", CustomizeBoxType.NORMAL, 120, List.of(new BellRequest(BellType.AFTER_START, 90, 1)), null, null, "콜리"), new CustomizeTimeBoxCreateRequest(Stance.CONS, "입론", CustomizeBoxType.NORMAL, - 120, List.of(new BellRequest(BellType.AFTER_START, 90, 1), new BellRequest(BellType.AFTER_START, 120, 2)), null, null, "비토"), + 120, List.of(new BellRequest(BellType.AFTER_START, 90, 1), + new BellRequest(BellType.AFTER_START, 120, 2)), null, null, "비토"), new CustomizeTimeBoxCreateRequest(Stance.NEUTRAL, "난상 토론", CustomizeBoxType.TIME_BASED, null, null, 360, 120, null), new CustomizeTimeBoxCreateRequest(Stance.NEUTRAL, "존중 토론", CustomizeBoxType.TIME_BASED, @@ -385,7 +390,8 @@ class UpdateTable { new CustomizeTimeBoxResponse(Stance.PROS, "입론", CustomizeBoxType.NORMAL, 120, List.of(new BellResponse(BellType.AFTER_START, 90, 1)), null, null, "콜리"), new CustomizeTimeBoxResponse(Stance.CONS, "입론", CustomizeBoxType.NORMAL, - 120, List.of(new BellResponse(BellType.AFTER_START, 90, 1), new BellResponse(BellType.AFTER_START, 120, 2)), null, null, "비토"), + 120, List.of(new BellResponse(BellType.AFTER_START, 90, 1), + new BellResponse(BellType.AFTER_START, 120, 2)), null, null, "비토"), new CustomizeTimeBoxResponse(Stance.NEUTRAL, "난상 토론", CustomizeBoxType.TIME_BASED, null, null, 360, 120, null), new CustomizeTimeBoxResponse(Stance.NEUTRAL, "존중 토론", CustomizeBoxType.TIME_BASED, @@ -432,7 +438,8 @@ class UpdateTable { new CustomizeTimeBoxCreateRequest(Stance.PROS, "입론", CustomizeBoxType.NORMAL, 120, List.of(new BellRequest(BellType.AFTER_START, 90, 1)), null, null, "콜리"), new CustomizeTimeBoxCreateRequest(Stance.CONS, "입론", CustomizeBoxType.NORMAL, - 120, List.of(new BellRequest(BellType.AFTER_START, 90, 1), new BellRequest(BellType.AFTER_START, 120, 2)), null, null, "비토"), + 120, List.of(new BellRequest(BellType.AFTER_START, 90, 1), + new BellRequest(BellType.AFTER_START, 120, 2)), null, null, "비토"), new CustomizeTimeBoxCreateRequest(Stance.NEUTRAL, "난상 토론", CustomizeBoxType.TIME_BASED, null, null, 360, 120, null), new CustomizeTimeBoxCreateRequest(Stance.NEUTRAL, "존중 토론", CustomizeBoxType.TIME_BASED, @@ -466,8 +473,8 @@ class Debate { ### 타임 박스 종류에 따른 웅답 값 | 타임 박스 종류 | 필수 입력 | 선택 입력 | null 입력 | | :---: | ---| --- | --- | - | 커스텀 타임 박스 | stance, speechType, boxType, time | speaker | timePerTeam, timePerSpeaking | - | 자유 토론 타임 박스 | stance, speechType, boxType, timePerTeam | speaker, timePerSpeaking | time | + | 커스텀 타임 박스 | stance, speechType, boxType, remainingTime | speaker | timePerTeam, timePerSpeaking | + | 자유 토론 타임 박스 | stance, speechType, boxType, timePerTeam | speaker, timePerSpeaking | remainingTime | """) .tag(Tag.CUSTOMIZE_API) .requestHeader( @@ -492,10 +499,10 @@ class Debate { fieldWithPath("table[].stance").type(STRING).description("입장"), fieldWithPath("table[].speechType").type(STRING).description("발언 유형"), fieldWithPath("table[].boxType").type(STRING).description("타임 박스 유형"), - fieldWithPath("table[].time").type(NUMBER).description("발언 시간(초)").optional(), + fieldWithPath("table[].remainingTime").type(NUMBER).description("발언 시간(초)").optional(), fieldWithPath("table[].bell").type(ARRAY).description("종소리 정보").optional(), fieldWithPath("table[].bell[].type").type(STRING).description("종소리 종류"), - fieldWithPath("table[].bell[].time").type(NUMBER).description("종소리 울릴 시간(초)"), + fieldWithPath("table[].bell[].remainingTime").type(NUMBER).description("종소리 울릴 시간(초)"), fieldWithPath("table[].bell[].count").type(NUMBER).description("종소리 횟수"), fieldWithPath("table[].timePerTeam").type(NUMBER).description("팀당 발언 시간 (초)").optional(), fieldWithPath("table[].timePerSpeaking").type(NUMBER).description("1회 발언 시간 (초)").optional(), @@ -514,7 +521,8 @@ class Debate { new CustomizeTimeBoxResponse(Stance.PROS, "입론", CustomizeBoxType.NORMAL, 120, List.of(new BellResponse(BellType.AFTER_START, 90, 1)), null, null, "콜리"), new CustomizeTimeBoxResponse(Stance.CONS, "입론", CustomizeBoxType.NORMAL, - 120, List.of(new BellResponse(BellType.AFTER_START, 90, 1), new BellResponse(BellType.AFTER_START, 120, 2)), null, null, "비토"), + 120, List.of(new BellResponse(BellType.AFTER_START, 90, 1), + new BellResponse(BellType.AFTER_START, 120, 2)), null, null, "비토"), new CustomizeTimeBoxResponse(Stance.NEUTRAL, "난상 토론", CustomizeBoxType.TIME_BASED, null, null, 360, 120, null), new CustomizeTimeBoxResponse(Stance.NEUTRAL, "존중 토론", CustomizeBoxType.TIME_BASED, diff --git a/src/test/java/com/debatetimer/controller/sharing/SharingControllerTest.java b/src/test/java/com/debatetimer/controller/sharing/SharingControllerTest.java index 5e4ab59e..207c90f8 100644 --- a/src/test/java/com/debatetimer/controller/sharing/SharingControllerTest.java +++ b/src/test/java/com/debatetimer/controller/sharing/SharingControllerTest.java @@ -53,7 +53,7 @@ class Share { () -> assertThat(response.data().timerType()).isEqualTo(request.data().timerType()), () -> assertThat(response.data().sequence()).isEqualTo(request.data().sequence()), () -> assertThat(response.data().currentTeam()).isEqualTo(request.data().currentTeam()), - () -> assertThat(response.data().time()).isEqualTo(request.data().time()) + () -> assertThat(response.data().remainingTime()).isEqualTo(request.data().remainingTime()) ); } @@ -76,7 +76,7 @@ class Share { () -> assertThat(response.data().timerType()).isEqualTo(request.data().timerType()), () -> assertThat(response.data().sequence()).isEqualTo(request.data().sequence()), () -> assertThat(response.data().currentTeam()).isEqualTo(request.data().currentTeam()), - () -> assertThat(response.data().time()).isEqualTo(request.data().time()) + () -> assertThat(response.data().remainingTime()).isEqualTo(request.data().remainingTime()) ); } From 6939a7f3019cf88cf965ea12e05c3c652fea8842 Mon Sep 17 00:00:00 2001 From: coli Date: Wed, 25 Mar 2026 01:15:02 +0900 Subject: [PATCH 07/15] =?UTF-8?q?refactor:=20eventData=EB=A5=BC=20?= =?UTF-8?q?=ED=86=B5=ED=95=9C=20=EC=BB=A8=ED=8A=B8=EB=A1=A4=EB=9F=AC?= =?UTF-8?q?=EC=97=90=EC=84=9C=EC=9D=98=20=EC=9D=91=EB=8B=B5=20=EB=B6=84?= =?UTF-8?q?=EA=B8=B0=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../debatetimer/controller/sharing/SharingController.java | 2 +- .../com/debatetimer/dto/sharing/request/SharingRequest.java | 6 ++++-- .../controller/sharing/SharingControllerTest.java | 5 +---- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/debatetimer/controller/sharing/SharingController.java b/src/main/java/com/debatetimer/controller/sharing/SharingController.java index 8a8d9ccd..8071c327 100644 --- a/src/main/java/com/debatetimer/controller/sharing/SharingController.java +++ b/src/main/java/com/debatetimer/controller/sharing/SharingController.java @@ -19,7 +19,7 @@ public SharingResponse share( @DestinationVariable(value = "roomId") long roomId, @Valid @Payload SharingRequest request ) { - if (!request.hasEvent()) { + if (!request.hasEventData()) { return new SharingResponse(request.eventType(), null); } diff --git a/src/main/java/com/debatetimer/dto/sharing/request/SharingRequest.java b/src/main/java/com/debatetimer/dto/sharing/request/SharingRequest.java index ec86e573..5907f879 100644 --- a/src/main/java/com/debatetimer/dto/sharing/request/SharingRequest.java +++ b/src/main/java/com/debatetimer/dto/sharing/request/SharingRequest.java @@ -4,9 +4,11 @@ import com.debatetimer.domain.sharing.TimerEventType; import jakarta.annotation.Nullable; import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import java.util.Optional; public record SharingRequest( + @NotNull TimerEventType eventType, @Valid @@ -14,8 +16,8 @@ public record SharingRequest( TimerEventInfoRequest data ) { - public boolean hasEvent() { - return eventType != null; + public boolean hasEventData() { + return data != null; } public TimerEventInfo toTimerEventInfo() { diff --git a/src/test/java/com/debatetimer/controller/sharing/SharingControllerTest.java b/src/test/java/com/debatetimer/controller/sharing/SharingControllerTest.java index 207c90f8..d0914e9e 100644 --- a/src/test/java/com/debatetimer/controller/sharing/SharingControllerTest.java +++ b/src/test/java/com/debatetimer/controller/sharing/SharingControllerTest.java @@ -73,10 +73,7 @@ class Share { assertAll( () -> assertThat(response.eventType()).isEqualTo(request.eventType()), - () -> assertThat(response.data().timerType()).isEqualTo(request.data().timerType()), - () -> assertThat(response.data().sequence()).isEqualTo(request.data().sequence()), - () -> assertThat(response.data().currentTeam()).isEqualTo(request.data().currentTeam()), - () -> assertThat(response.data().remainingTime()).isEqualTo(request.data().remainingTime()) + () -> assertThat(response.data()).isNull() ); } From f9235ac4ed62e8b92770350ad4b9c1923a89bd3a Mon Sep 17 00:00:00 2001 From: coli Date: Wed, 25 Mar 2026 01:17:35 +0900 Subject: [PATCH 08/15] =?UTF-8?q?feat:=20service=20=EA=B3=84=EC=B8=B5?= =?UTF-8?q?=EC=9D=84=20=ED=86=B5=ED=95=B4=20=EC=9D=91=EB=8B=B5=20=EB=B0=98?= =?UTF-8?q?=ED=99=98=EB=A1=9C=EC=A7=81=20=EC=B6=94=EC=83=81=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/sharing/SharingController.java | 14 ++++++------- .../service/sharing/SharingService.java | 21 +++++++++++++++++++ 2 files changed, 27 insertions(+), 8 deletions(-) create mode 100644 src/main/java/com/debatetimer/service/sharing/SharingService.java diff --git a/src/main/java/com/debatetimer/controller/sharing/SharingController.java b/src/main/java/com/debatetimer/controller/sharing/SharingController.java index 8071c327..0216a15b 100644 --- a/src/main/java/com/debatetimer/controller/sharing/SharingController.java +++ b/src/main/java/com/debatetimer/controller/sharing/SharingController.java @@ -2,8 +2,9 @@ import com.debatetimer.dto.sharing.request.SharingRequest; import com.debatetimer.dto.sharing.response.SharingResponse; -import com.debatetimer.dto.sharing.response.TimerEventInfoResponse; +import com.debatetimer.service.sharing.SharingService; import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; import org.springframework.messaging.handler.annotation.DestinationVariable; import org.springframework.messaging.handler.annotation.MessageMapping; import org.springframework.messaging.handler.annotation.Payload; @@ -11,21 +12,18 @@ import org.springframework.stereotype.Controller; @Controller +@RequiredArgsConstructor public class SharingController { + private final SharingService sharingService; + @MessageMapping("/event/{roomId}") @SendTo("/room/{roomId}") public SharingResponse share( @DestinationVariable(value = "roomId") long roomId, @Valid @Payload SharingRequest request ) { - if (!request.hasEventData()) { - return new SharingResponse(request.eventType(), null); - } - return new SharingResponse( - request.eventType(), - new TimerEventInfoResponse(request.toTimerEventInfo()) - ); + return sharingService.share(request); } } diff --git a/src/main/java/com/debatetimer/service/sharing/SharingService.java b/src/main/java/com/debatetimer/service/sharing/SharingService.java new file mode 100644 index 00000000..e1b5a4d9 --- /dev/null +++ b/src/main/java/com/debatetimer/service/sharing/SharingService.java @@ -0,0 +1,21 @@ +package com.debatetimer.service.sharing; + +import com.debatetimer.dto.sharing.request.SharingRequest; +import com.debatetimer.dto.sharing.response.SharingResponse; +import com.debatetimer.dto.sharing.response.TimerEventInfoResponse; +import org.springframework.stereotype.Service; + +@Service +public class SharingService { + + public SharingResponse share(SharingRequest request) { + if (!request.hasEventData()) { + return new SharingResponse(request.eventType(), null); + } + + return new SharingResponse( + request.eventType(), + new TimerEventInfoResponse(request.toTimerEventInfo()) + ); + } +} From 9bf17a8e0ebaeb10300199dd6c496870eb69a86a Mon Sep 17 00:00:00 2001 From: coli Date: Wed, 25 Mar 2026 01:23:19 +0900 Subject: [PATCH 09/15] =?UTF-8?q?refactor:=20eventInfo=EB=A5=BC=20Optional?= =?UTF-8?q?=EB=A1=9C=20=EB=B0=98=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/sharing/request/SharingRequest.java | 9 ++------- .../debatetimer/service/sharing/SharingService.java | 13 ++++++------- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/debatetimer/dto/sharing/request/SharingRequest.java b/src/main/java/com/debatetimer/dto/sharing/request/SharingRequest.java index 5907f879..b77a5de9 100644 --- a/src/main/java/com/debatetimer/dto/sharing/request/SharingRequest.java +++ b/src/main/java/com/debatetimer/dto/sharing/request/SharingRequest.java @@ -16,13 +16,8 @@ public record SharingRequest( TimerEventInfoRequest data ) { - public boolean hasEventData() { - return data != null; - } - - public TimerEventInfo toTimerEventInfo() { + public Optional toTimerEventInfo() { return Optional.ofNullable(data) - .map(TimerEventInfoRequest::toTimerEventInfo) - .orElse(null); + .map(TimerEventInfoRequest::toTimerEventInfo); } } diff --git a/src/main/java/com/debatetimer/service/sharing/SharingService.java b/src/main/java/com/debatetimer/service/sharing/SharingService.java index e1b5a4d9..1fcedb4d 100644 --- a/src/main/java/com/debatetimer/service/sharing/SharingService.java +++ b/src/main/java/com/debatetimer/service/sharing/SharingService.java @@ -9,13 +9,12 @@ public class SharingService { public SharingResponse share(SharingRequest request) { - if (!request.hasEventData()) { - return new SharingResponse(request.eventType(), null); - } - return new SharingResponse( - request.eventType(), - new TimerEventInfoResponse(request.toTimerEventInfo()) - ); + return request.toTimerEventInfo() + .map(eventInfo -> new SharingResponse( + request.eventType(), + new TimerEventInfoResponse(eventInfo) + )) + .orElse(new SharingResponse(request.eventType(), null)); } } From c07934248666291d42a52f2ebd099e73cd80103c Mon Sep 17 00:00:00 2001 From: coli Date: Wed, 25 Mar 2026 01:27:00 +0900 Subject: [PATCH 10/15] =?UTF-8?q?refactor:=20dto=20=EC=A0=95=EB=A0=AC=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/sharing/request/TimerEventInfoRequest.java | 8 ++++++-- .../dto/sharing/response/TimerEventInfoResponse.java | 10 +++++++--- .../controller/sharing/SharingControllerTest.java | 4 ++-- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/debatetimer/dto/sharing/request/TimerEventInfoRequest.java b/src/main/java/com/debatetimer/dto/sharing/request/TimerEventInfoRequest.java index 1cf85ae4..28becf30 100644 --- a/src/main/java/com/debatetimer/dto/sharing/request/TimerEventInfoRequest.java +++ b/src/main/java/com/debatetimer/dto/sharing/request/TimerEventInfoRequest.java @@ -7,9 +7,13 @@ import jakarta.validation.constraints.NotNull; public record TimerEventInfoRequest( - @NotNull CustomizeBoxType timerType, + @NotNull + CustomizeBoxType timerType, + + @Nullable + Stance currentTeam, + int sequence, - @Nullable Stance currentTeam, long remainingTime ) { diff --git a/src/main/java/com/debatetimer/dto/sharing/response/TimerEventInfoResponse.java b/src/main/java/com/debatetimer/dto/sharing/response/TimerEventInfoResponse.java index 617bda80..9ad31213 100644 --- a/src/main/java/com/debatetimer/dto/sharing/response/TimerEventInfoResponse.java +++ b/src/main/java/com/debatetimer/dto/sharing/response/TimerEventInfoResponse.java @@ -8,17 +8,21 @@ import jakarta.validation.constraints.NotNull; public record TimerEventInfoResponse( - @NotNull CustomizeBoxType timerType, + @NotNull + CustomizeBoxType timerType, + + @Nullable + Stance currentTeam, + int sequence, - @Nullable Stance currentTeam, long remainingTime ) { public TimerEventInfoResponse(TimerEventInfo timerEventInfo) { this( timerEventInfo.getTimerType(), - timerEventInfo.getSequence(), timerEventInfo.getCurrentTeam(), + timerEventInfo.getSequence(), timerEventInfo.getRemainingTime() ); } diff --git a/src/test/java/com/debatetimer/controller/sharing/SharingControllerTest.java b/src/test/java/com/debatetimer/controller/sharing/SharingControllerTest.java index d0914e9e..5ae95913 100644 --- a/src/test/java/com/debatetimer/controller/sharing/SharingControllerTest.java +++ b/src/test/java/com/debatetimer/controller/sharing/SharingControllerTest.java @@ -36,8 +36,8 @@ class Share { TimerEventType.NEXT, new TimerEventInfoRequest( CustomizeBoxType.NORMAL, - 2, null, + 2, 30 ) ); @@ -88,8 +88,8 @@ class Share { TimerEventType.NEXT, new TimerEventInfoRequest( boxType, - 2, null, + 2, 30 ) ); From 1dbb47afdc5bc59c9c7e8f169c7f037c76006a89 Mon Sep 17 00:00:00 2001 From: coli Date: Wed, 25 Mar 2026 01:41:36 +0900 Subject: [PATCH 11/15] =?UTF-8?q?fix:=20=EA=B0=99=EC=9D=B4=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD=EB=90=98=EC=97=88=EB=8D=98=20remainingTime=20?= =?UTF-8?q?=ED=95=84=EB=93=9C=EB=AA=85=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/BaseControllerTest.java | 4 +- .../customize/CustomizeDocumentTest.java | 40 +++++++++---------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/test/java/com/debatetimer/controller/BaseControllerTest.java b/src/test/java/com/debatetimer/controller/BaseControllerTest.java index ab03fbaa..2c43b995 100644 --- a/src/test/java/com/debatetimer/controller/BaseControllerTest.java +++ b/src/test/java/com/debatetimer/controller/BaseControllerTest.java @@ -124,7 +124,7 @@ private ArbitraryBuilder getCustomizeTimeBoxCreat .set("stance", Stance.PROS) .set("speechType", "입론1") .set("boxType", CustomizeBoxType.NORMAL) - .set("remainingTime", 120) + .set("time", 120) .set("bell", getBellRequestBuilder().sampleList(2)) .set("timePerTeam", 60) .set("timePerSpeaking", null) @@ -134,7 +134,7 @@ private ArbitraryBuilder getCustomizeTimeBoxCreat private ArbitraryBuilder getBellRequestBuilder() { return fixtureMonkey.giveMeBuilder(BellRequest.class) .set("type", BellType.AFTER_START) - .set("remainingTime", 30) + .set("time", 30) .set("count", 1); } } diff --git a/src/test/java/com/debatetimer/controller/customize/CustomizeDocumentTest.java b/src/test/java/com/debatetimer/controller/customize/CustomizeDocumentTest.java index 113144e0..dc565166 100644 --- a/src/test/java/com/debatetimer/controller/customize/CustomizeDocumentTest.java +++ b/src/test/java/com/debatetimer/controller/customize/CustomizeDocumentTest.java @@ -52,8 +52,8 @@ class Save { ### 타임 박스 종류에 따른 요청 값 | 타임 박스 종류 | 필수 입력 | 선택 입력 | null 입력 | | :---: | ---| --- | --- | - | 커스텀 타임 박스 | stance, speechType, boxType, remainingTime | speaker | timePerTeam, timePerSpeaking | - | 자유 토론 타임 박스 | stance, speechType, boxType, timePerTeam | speaker, timePerSpeaking | remainingTime | + | 커스텀 타임 박스 | stance, speechType, boxType, time | speaker | timePerTeam, timePerSpeaking | + | 자유 토론 타임 박스 | stance, speechType, boxType, timePerTeam | speaker, timePerSpeaking | time | """) .requestHeader( headerWithName(HttpHeaders.AUTHORIZATION).description("액세스 토큰") @@ -70,10 +70,10 @@ class Save { fieldWithPath("table[].stance").type(STRING).description("입장"), fieldWithPath("table[].speechType").type(STRING).description("발언 유형"), fieldWithPath("table[].boxType").type(STRING).description("타임 박스 유형"), - fieldWithPath("table[].remainingTime").type(NUMBER).description("발언 시간(초)").optional(), + fieldWithPath("table[].time").type(NUMBER).description("발언 시간(초)").optional(), fieldWithPath("table[].bell").type(ARRAY).description("종소리 정보").optional(), fieldWithPath("table[].bell[].type").type(STRING).description("종소리 종류"), - fieldWithPath("table[].bell[].remainingTime").type(NUMBER).description("종소리 울릴 시간(초)"), + fieldWithPath("table[].bell[].time").type(NUMBER).description("종소리 울릴 시간(초)"), fieldWithPath("table[].bell[].count").type(NUMBER).description("종소리 횟수"), fieldWithPath("table[].timePerTeam").type(NUMBER).description("팀당 발언 시간 (초)").optional(), fieldWithPath("table[].timePerSpeaking").type(NUMBER).description("1회 발언 시간 (초)").optional(), @@ -95,10 +95,10 @@ class Save { fieldWithPath("table[].stance").type(STRING).description("입장"), fieldWithPath("table[].speechType").type(STRING).description("발언 유형"), fieldWithPath("table[].boxType").type(STRING).description("타임 박스 유형"), - fieldWithPath("table[].remainingTime").type(NUMBER).description("발언 시간(초)").optional(), + fieldWithPath("table[].time").type(NUMBER).description("발언 시간(초)").optional(), fieldWithPath("table[].bell").type(ARRAY).description("종소리 정보").optional(), fieldWithPath("table[].bell[].type").type(STRING).description("종소리 종류"), - fieldWithPath("table[].bell[].remainingTime").type(NUMBER).description("종소리 울릴 시간(초)"), + fieldWithPath("table[].bell[].time").type(NUMBER).description("종소리 울릴 시간(초)"), fieldWithPath("table[].bell[].count").type(NUMBER).description("종소리 횟수"), fieldWithPath("table[].timePerTeam").type(NUMBER).description("팀당 발언 시간 (초)").optional(), fieldWithPath("table[].timePerSpeaking").type(NUMBER).description("1회 발언 시간 (초)").optional(), @@ -208,8 +208,8 @@ class GetTable { ### 타임 박스 종류에 따른 웅답 값 | 타임 박스 종류 | 필수 입력 | 선택 입력 | null 입력 | | :---: | ---| --- | --- | - | 커스텀 타임 박스 | stance, speechType, boxType, remainingTime | speaker | timePerTeam, timePerSpeaking | - | 자유 토론 타임 박스 | stance, speechType, boxType, timePerTeam | speaker, timePerSpeaking | remainingTime | + | 커스텀 타임 박스 | stance, speechType, boxType, time | speaker | timePerTeam, timePerSpeaking | + | 자유 토론 타임 박스 | stance, speechType, boxType, timePerTeam | speaker, timePerSpeaking | time | """) .tag(Tag.CUSTOMIZE_API) .requestHeader( @@ -234,10 +234,10 @@ class GetTable { fieldWithPath("table[].stance").type(STRING).description("입장"), fieldWithPath("table[].speechType").type(STRING).description("발언 유형"), fieldWithPath("table[].boxType").type(STRING).description("타임 박스 유형"), - fieldWithPath("table[].remainingTime").type(NUMBER).description("발언 시간(초)").optional(), + fieldWithPath("table[].time").type(NUMBER).description("발언 시간(초)").optional(), fieldWithPath("table[].bell").type(ARRAY).description("종소리 정보").optional(), fieldWithPath("table[].bell[].type").type(STRING).description("종소리 종류"), - fieldWithPath("table[].bell[].remainingTime").type(NUMBER).description("종소리 울릴 시간(초)"), + fieldWithPath("table[].bell[].time").type(NUMBER).description("종소리 울릴 시간(초)"), fieldWithPath("table[].bell[].count").type(NUMBER).description("종소리 횟수"), fieldWithPath("table[].timePerTeam").type(NUMBER).description("팀당 발언 시간 (초)").optional(), fieldWithPath("table[].timePerSpeaking").type(NUMBER).description("1회 발언 시간 (초)").optional(), @@ -308,8 +308,8 @@ class UpdateTable { ### 타임 박스 종류에 따른 요청/웅답 값 | 타임 박스 종류 | 필수 입력 | 선택 입력 | null 입력 | | :---: | ---| --- | --- | - | 커스텀 타임 박스 | stance, speechType, boxType, remainingTime | speaker | timePerTeam, timePerSpeaking | - | 자유 토론 타임 박스 | stance, speechType, boxType, timePerTeam | speaker, timePerSpeaking | remainingTime | + | 커스텀 타임 박스 | stance, speechType, boxType, time | speaker | timePerTeam, timePerSpeaking | + | 자유 토론 타임 박스 | stance, speechType, boxType, timePerTeam | speaker, timePerSpeaking | time | """) .requestHeader( headerWithName(HttpHeaders.AUTHORIZATION).description("액세스 토큰") @@ -329,10 +329,10 @@ class UpdateTable { fieldWithPath("table[].stance").type(STRING).description("입장"), fieldWithPath("table[].speechType").type(STRING).description("발언 유형"), fieldWithPath("table[].boxType").type(STRING).description("타임 박스 유형"), - fieldWithPath("table[].remainingTime").type(NUMBER).description("발언 시간(초)").optional(), + fieldWithPath("table[].time").type(NUMBER).description("발언 시간(초)").optional(), fieldWithPath("table[].bell").type(ARRAY).description("종소리 정보").optional(), fieldWithPath("table[].bell[].type").type(STRING).description("종소리 종류"), - fieldWithPath("table[].bell[].remainingTime").type(NUMBER).description("종소리 울릴 시간(초)"), + fieldWithPath("table[].bell[].time").type(NUMBER).description("종소리 울릴 시간(초)"), fieldWithPath("table[].bell[].count").type(NUMBER).description("종소리 횟수"), fieldWithPath("table[].timePerTeam").type(NUMBER).description("팀당 발언 시간 (초)").optional(), fieldWithPath("table[].timePerSpeaking").type(NUMBER).description("1회 발언 시간 (초)").optional(), @@ -354,10 +354,10 @@ class UpdateTable { fieldWithPath("table[].stance").type(STRING).description("입장"), fieldWithPath("table[].speechType").type(STRING).description("발언 유형"), fieldWithPath("table[].boxType").type(STRING).description("타임 박스 유형"), - fieldWithPath("table[].remainingTime").type(NUMBER).description("발언 시간(초)").optional(), + fieldWithPath("table[].time").type(NUMBER).description("발언 시간(초)").optional(), fieldWithPath("table[].bell").type(ARRAY).description("종소리 정보").optional(), fieldWithPath("table[].bell[].type").type(STRING).description("종소리 종류"), - fieldWithPath("table[].bell[].remainingTime").type(NUMBER).description("종소리 울릴 시간(초)"), + fieldWithPath("table[].bell[].time").type(NUMBER).description("종소리 울릴 시간(초)"), fieldWithPath("table[].bell[].count").type(NUMBER).description("종소리 횟수"), fieldWithPath("table[].timePerTeam").type(NUMBER).description("팀당 발언 시간 (초)").optional(), fieldWithPath("table[].timePerSpeaking").type(NUMBER).description("1회 발언 시간 (초)").optional(), @@ -473,8 +473,8 @@ class Debate { ### 타임 박스 종류에 따른 웅답 값 | 타임 박스 종류 | 필수 입력 | 선택 입력 | null 입력 | | :---: | ---| --- | --- | - | 커스텀 타임 박스 | stance, speechType, boxType, remainingTime | speaker | timePerTeam, timePerSpeaking | - | 자유 토론 타임 박스 | stance, speechType, boxType, timePerTeam | speaker, timePerSpeaking | remainingTime | + | 커스텀 타임 박스 | stance, speechType, boxType, time | speaker | timePerTeam, timePerSpeaking | + | 자유 토론 타임 박스 | stance, speechType, boxType, timePerTeam | speaker, timePerSpeaking | time | """) .tag(Tag.CUSTOMIZE_API) .requestHeader( @@ -499,10 +499,10 @@ class Debate { fieldWithPath("table[].stance").type(STRING).description("입장"), fieldWithPath("table[].speechType").type(STRING).description("발언 유형"), fieldWithPath("table[].boxType").type(STRING).description("타임 박스 유형"), - fieldWithPath("table[].remainingTime").type(NUMBER).description("발언 시간(초)").optional(), + fieldWithPath("table[].time").type(NUMBER).description("발언 시간(초)").optional(), fieldWithPath("table[].bell").type(ARRAY).description("종소리 정보").optional(), fieldWithPath("table[].bell[].type").type(STRING).description("종소리 종류"), - fieldWithPath("table[].bell[].remainingTime").type(NUMBER).description("종소리 울릴 시간(초)"), + fieldWithPath("table[].bell[].time").type(NUMBER).description("종소리 울릴 시간(초)"), fieldWithPath("table[].bell[].count").type(NUMBER).description("종소리 횟수"), fieldWithPath("table[].timePerTeam").type(NUMBER).description("팀당 발언 시간 (초)").optional(), fieldWithPath("table[].timePerSpeaking").type(NUMBER).description("1회 발언 시간 (초)").optional(), From 59051a9d7b5eaed30293f301eeb93ffc2acbb95d Mon Sep 17 00:00:00 2001 From: coli Date: Mon, 30 Mar 2026 18:33:43 +0900 Subject: [PATCH 12/15] =?UTF-8?q?feat:=20timerEventInfo=20type=EB=B3=84=20?= =?UTF-8?q?=ED=8C=8C=EB=9D=BC=EB=AF=B8=ED=84=B0=20nullable=20=EA=B2=80?= =?UTF-8?q?=EC=A6=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/sharing/TimerEventInfo.java | 27 ++++++++++++- .../exception/errorcode/ClientErrorCode.java | 4 +- .../domain/sharing/TimerEventInfoTest.java | 39 +++++++++++++++++++ 3 files changed, 67 insertions(+), 3 deletions(-) create mode 100644 src/test/java/com/debatetimer/domain/sharing/TimerEventInfoTest.java diff --git a/src/main/java/com/debatetimer/domain/sharing/TimerEventInfo.java b/src/main/java/com/debatetimer/domain/sharing/TimerEventInfo.java index 741f9212..0ddb9c0f 100644 --- a/src/main/java/com/debatetimer/domain/sharing/TimerEventInfo.java +++ b/src/main/java/com/debatetimer/domain/sharing/TimerEventInfo.java @@ -2,13 +2,13 @@ import com.debatetimer.domain.customize.CustomizeBoxType; import com.debatetimer.domain.customize.Stance; +import com.debatetimer.exception.custom.DTClientErrorException; +import com.debatetimer.exception.errorcode.ClientErrorCode; import jakarta.annotation.Nullable; import jakarta.validation.constraints.NotNull; import lombok.Getter; -import lombok.RequiredArgsConstructor; @Getter -@RequiredArgsConstructor public class TimerEventInfo { @NotNull @@ -20,4 +20,27 @@ public class TimerEventInfo { private final Stance currentTeam; private final long remainingTime; + + public TimerEventInfo( + CustomizeBoxType timerType, + int sequence, + @Nullable Stance currentTeam, + long remainingTime + ) { + validateCurrentTeam(timerType, currentTeam); + this.timerType = timerType; + this.sequence = sequence; + this.currentTeam = currentTeam; + this.remainingTime = remainingTime; + } + + private void validateCurrentTeam(CustomizeBoxType timerType, Stance currentTeam) { + if (timerType.isTimeBased() && currentTeam == null) { + throw new DTClientErrorException(ClientErrorCode.INVALID_TIME_BASED_TIMER_EVENT_INFO); + } + + if (!timerType.isTimeBased() && currentTeam != null) { + throw new DTClientErrorException(ClientErrorCode.INVALID_NORMAL_TIMER_EVENT_INFO); + } + } } diff --git a/src/main/java/com/debatetimer/exception/errorcode/ClientErrorCode.java b/src/main/java/com/debatetimer/exception/errorcode/ClientErrorCode.java index 5bf7d05b..40965fa8 100644 --- a/src/main/java/com/debatetimer/exception/errorcode/ClientErrorCode.java +++ b/src/main/java/com/debatetimer/exception/errorcode/ClientErrorCode.java @@ -77,7 +77,9 @@ public enum ClientErrorCode implements ResponseErrorCode { INVALID_BELL_TIME(HttpStatus.BAD_REQUEST, "벨 시간은 0 이상의 정수여야 합니다."), INVALID_BELL_COUNT(HttpStatus.BAD_REQUEST, "벨 카운트는 1 이상 %d 이하의 정수여야 합니다.".formatted(Bell.MAX_BELL_COUNT)), - ; + + INVALID_NORMAL_TIMER_EVENT_INFO(HttpStatus.BAD_REQUEST, "잘못된 일반 타이머 이벤트 데이터입니다"), + INVALID_TIME_BASED_TIMER_EVENT_INFO(HttpStatus.BAD_REQUEST, "잘못된 자유토론 타이머 이벤트 데이터입니다"); private final HttpStatus status; private final String message; diff --git a/src/test/java/com/debatetimer/domain/sharing/TimerEventInfoTest.java b/src/test/java/com/debatetimer/domain/sharing/TimerEventInfoTest.java new file mode 100644 index 00000000..8a6cd764 --- /dev/null +++ b/src/test/java/com/debatetimer/domain/sharing/TimerEventInfoTest.java @@ -0,0 +1,39 @@ +package com.debatetimer.domain.sharing; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import com.debatetimer.domain.customize.CustomizeBoxType; +import com.debatetimer.domain.customize.Stance; +import com.debatetimer.exception.custom.DTClientErrorException; +import com.debatetimer.exception.errorcode.ClientErrorCode; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +class TimerEventInfoTest { + + @Nested + class ValidateCurrentTeam { + + @Test + void 일반_타이머의_경우_현재_발언팀이_입력되면_안된다() { + assertThatThrownBy(() -> new TimerEventInfo( + CustomizeBoxType.NORMAL, + 2, + Stance.CONS, + 30L + )).isInstanceOf(DTClientErrorException.class) + .hasMessage(ClientErrorCode.INVALID_NORMAL_TIMER_EVENT_INFO.getMessage()); + } + + @Test + void 자유토론_타이머의_경우_현재_발언팀이_입력되어야_한다() { + assertThatThrownBy(() -> new TimerEventInfo( + CustomizeBoxType.TIME_BASED, + 2, + null, + 30L + )).isInstanceOf(DTClientErrorException.class) + .hasMessage(ClientErrorCode.INVALID_TIME_BASED_TIMER_EVENT_INFO.getMessage()); + } + } +} From 53ba91797b705d2a37c34c26c4c46ca66138600f Mon Sep 17 00:00:00 2001 From: coli Date: Mon, 30 Mar 2026 19:02:09 +0900 Subject: [PATCH 13/15] =?UTF-8?q?feat:=20timerEvent=20=EB=8F=84=EB=A9=94?= =?UTF-8?q?=EC=9D=B8=20=EA=B0=9D=EC=B2=B4=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/sharing/TimerEvent.java | 24 +++++++++++++++ ...imerEventInfo.java => TimerEventData.java} | 8 ++--- .../domain/sharing/TimerEventType.java | 30 ++++++++++++++----- .../dto/sharing/request/SharingRequest.java | 12 ++++++-- .../request/TimerEventInfoRequest.java | 6 ++-- .../dto/sharing/response/SharingResponse.java | 5 +++- ...ponse.java => TimerEventDataResponse.java} | 6 ++-- .../exception/errorcode/ClientErrorCode.java | 6 ++-- .../service/sharing/SharingService.java | 12 ++++---- ...tInfoTest.java => TimerEventDataTest.java} | 10 +++---- 10 files changed, 87 insertions(+), 32 deletions(-) create mode 100644 src/main/java/com/debatetimer/domain/sharing/TimerEvent.java rename src/main/java/com/debatetimer/domain/sharing/{TimerEventInfo.java => TimerEventData.java} (91%) rename src/main/java/com/debatetimer/dto/sharing/response/{TimerEventInfoResponse.java => TimerEventDataResponse.java} (79%) rename src/test/java/com/debatetimer/domain/sharing/{TimerEventInfoTest.java => TimerEventDataTest.java} (85%) diff --git a/src/main/java/com/debatetimer/domain/sharing/TimerEvent.java b/src/main/java/com/debatetimer/domain/sharing/TimerEvent.java new file mode 100644 index 00000000..c38b0da7 --- /dev/null +++ b/src/main/java/com/debatetimer/domain/sharing/TimerEvent.java @@ -0,0 +1,24 @@ +package com.debatetimer.domain.sharing; + +import jakarta.annotation.Nullable; +import jakarta.validation.constraints.NotNull; +import lombok.Getter; + +@Getter +public class TimerEvent { + + @NotNull + private final TimerEventType eventType; + + @Nullable + private final TimerEventData timerEventData; + + public TimerEvent( + TimerEventType eventType, + @Nullable TimerEventData timerEventData + ) { + eventType.validateEventData(timerEventData); + this.eventType = eventType; + this.timerEventData = timerEventData; + } +} diff --git a/src/main/java/com/debatetimer/domain/sharing/TimerEventInfo.java b/src/main/java/com/debatetimer/domain/sharing/TimerEventData.java similarity index 91% rename from src/main/java/com/debatetimer/domain/sharing/TimerEventInfo.java rename to src/main/java/com/debatetimer/domain/sharing/TimerEventData.java index 0ddb9c0f..85de556b 100644 --- a/src/main/java/com/debatetimer/domain/sharing/TimerEventInfo.java +++ b/src/main/java/com/debatetimer/domain/sharing/TimerEventData.java @@ -9,7 +9,7 @@ import lombok.Getter; @Getter -public class TimerEventInfo { +public class TimerEventData { @NotNull private final CustomizeBoxType timerType; @@ -21,7 +21,7 @@ public class TimerEventInfo { private final long remainingTime; - public TimerEventInfo( + public TimerEventData( CustomizeBoxType timerType, int sequence, @Nullable Stance currentTeam, @@ -36,11 +36,11 @@ public TimerEventInfo( private void validateCurrentTeam(CustomizeBoxType timerType, Stance currentTeam) { if (timerType.isTimeBased() && currentTeam == null) { - throw new DTClientErrorException(ClientErrorCode.INVALID_TIME_BASED_TIMER_EVENT_INFO); + throw new DTClientErrorException(ClientErrorCode.INVALID_TIME_BASED_TIMER_EVENT_DATA); } if (!timerType.isTimeBased() && currentTeam != null) { - throw new DTClientErrorException(ClientErrorCode.INVALID_NORMAL_TIMER_EVENT_INFO); + throw new DTClientErrorException(ClientErrorCode.INVALID_NORMAL_TIMER_EVENT_DATA); } } } diff --git a/src/main/java/com/debatetimer/domain/sharing/TimerEventType.java b/src/main/java/com/debatetimer/domain/sharing/TimerEventType.java index 33e1c5dd..ca1a5427 100644 --- a/src/main/java/com/debatetimer/domain/sharing/TimerEventType.java +++ b/src/main/java/com/debatetimer/domain/sharing/TimerEventType.java @@ -1,12 +1,28 @@ package com.debatetimer.domain.sharing; +import com.debatetimer.exception.custom.DTClientErrorException; +import com.debatetimer.exception.errorcode.ClientErrorCode; +import java.util.Objects; +import java.util.function.Predicate; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor public enum TimerEventType { - NEXT, - BEFORE, - STOP, - PLAY, - RESET, - TEAM_SWITCH, - FINISHED + NEXT(Objects::nonNull), + BEFORE(Objects::nonNull), + STOP(Objects::nonNull), + PLAY(Objects::nonNull), + RESET(Objects::nonNull), + TEAM_SWITCH(Objects::nonNull), + FINISHED(Objects::isNull), + ; + + private final Predicate eventDataValidator; + + public void validateEventData(Object eventData) { + if (!eventDataValidator.test(eventData)) { + throw new DTClientErrorException(ClientErrorCode.INVALID_TIMER_EVENT); + } + } } diff --git a/src/main/java/com/debatetimer/dto/sharing/request/SharingRequest.java b/src/main/java/com/debatetimer/dto/sharing/request/SharingRequest.java index b77a5de9..fd68faf4 100644 --- a/src/main/java/com/debatetimer/dto/sharing/request/SharingRequest.java +++ b/src/main/java/com/debatetimer/dto/sharing/request/SharingRequest.java @@ -1,6 +1,7 @@ package com.debatetimer.dto.sharing.request; -import com.debatetimer.domain.sharing.TimerEventInfo; +import com.debatetimer.domain.sharing.TimerEvent; +import com.debatetimer.domain.sharing.TimerEventData; import com.debatetimer.domain.sharing.TimerEventType; import jakarta.annotation.Nullable; import jakarta.validation.Valid; @@ -16,7 +17,14 @@ public record SharingRequest( TimerEventInfoRequest data ) { - public Optional toTimerEventInfo() { + public TimerEvent toTimerEvent() { + return Optional.ofNullable(data) + .map(TimerEventInfoRequest::toTimerEventInfo) + .map(eventData -> new TimerEvent(eventType, eventData)) + .orElse(new TimerEvent(eventType, null)); + } + + public Optional toTimerEventInfo() { return Optional.ofNullable(data) .map(TimerEventInfoRequest::toTimerEventInfo); } diff --git a/src/main/java/com/debatetimer/dto/sharing/request/TimerEventInfoRequest.java b/src/main/java/com/debatetimer/dto/sharing/request/TimerEventInfoRequest.java index 28becf30..6a4c591e 100644 --- a/src/main/java/com/debatetimer/dto/sharing/request/TimerEventInfoRequest.java +++ b/src/main/java/com/debatetimer/dto/sharing/request/TimerEventInfoRequest.java @@ -2,7 +2,7 @@ import com.debatetimer.domain.customize.CustomizeBoxType; import com.debatetimer.domain.customize.Stance; -import com.debatetimer.domain.sharing.TimerEventInfo; +import com.debatetimer.domain.sharing.TimerEventData; import jakarta.annotation.Nullable; import jakarta.validation.constraints.NotNull; @@ -17,8 +17,8 @@ public record TimerEventInfoRequest( long remainingTime ) { - public TimerEventInfo toTimerEventInfo() { - return new TimerEventInfo( + public TimerEventData toTimerEventInfo() { + return new TimerEventData( timerType, sequence, currentTeam, diff --git a/src/main/java/com/debatetimer/dto/sharing/response/SharingResponse.java b/src/main/java/com/debatetimer/dto/sharing/response/SharingResponse.java index 71a2d43e..2973fb94 100644 --- a/src/main/java/com/debatetimer/dto/sharing/response/SharingResponse.java +++ b/src/main/java/com/debatetimer/dto/sharing/response/SharingResponse.java @@ -7,7 +7,10 @@ public record SharingResponse( TimerEventType eventType, @Nullable - TimerEventInfoResponse data + TimerEventDataResponse data ) { + public SharingResponse(TimerEventType eventType) { + this(eventType, null); + } } diff --git a/src/main/java/com/debatetimer/dto/sharing/response/TimerEventInfoResponse.java b/src/main/java/com/debatetimer/dto/sharing/response/TimerEventDataResponse.java similarity index 79% rename from src/main/java/com/debatetimer/dto/sharing/response/TimerEventInfoResponse.java rename to src/main/java/com/debatetimer/dto/sharing/response/TimerEventDataResponse.java index 9ad31213..5fde093a 100644 --- a/src/main/java/com/debatetimer/dto/sharing/response/TimerEventInfoResponse.java +++ b/src/main/java/com/debatetimer/dto/sharing/response/TimerEventDataResponse.java @@ -3,11 +3,11 @@ import com.debatetimer.domain.customize.CustomizeBoxType; import com.debatetimer.domain.customize.Stance; -import com.debatetimer.domain.sharing.TimerEventInfo; +import com.debatetimer.domain.sharing.TimerEventData; import jakarta.annotation.Nullable; import jakarta.validation.constraints.NotNull; -public record TimerEventInfoResponse( +public record TimerEventDataResponse( @NotNull CustomizeBoxType timerType, @@ -18,7 +18,7 @@ public record TimerEventInfoResponse( long remainingTime ) { - public TimerEventInfoResponse(TimerEventInfo timerEventInfo) { + public TimerEventDataResponse(TimerEventData timerEventInfo) { this( timerEventInfo.getTimerType(), timerEventInfo.getCurrentTeam(), diff --git a/src/main/java/com/debatetimer/exception/errorcode/ClientErrorCode.java b/src/main/java/com/debatetimer/exception/errorcode/ClientErrorCode.java index 40965fa8..6079ba2f 100644 --- a/src/main/java/com/debatetimer/exception/errorcode/ClientErrorCode.java +++ b/src/main/java/com/debatetimer/exception/errorcode/ClientErrorCode.java @@ -78,8 +78,10 @@ public enum ClientErrorCode implements ResponseErrorCode { INVALID_BELL_TIME(HttpStatus.BAD_REQUEST, "벨 시간은 0 이상의 정수여야 합니다."), INVALID_BELL_COUNT(HttpStatus.BAD_REQUEST, "벨 카운트는 1 이상 %d 이하의 정수여야 합니다.".formatted(Bell.MAX_BELL_COUNT)), - INVALID_NORMAL_TIMER_EVENT_INFO(HttpStatus.BAD_REQUEST, "잘못된 일반 타이머 이벤트 데이터입니다"), - INVALID_TIME_BASED_TIMER_EVENT_INFO(HttpStatus.BAD_REQUEST, "잘못된 자유토론 타이머 이벤트 데이터입니다"); + INVALID_NORMAL_TIMER_EVENT_DATA(HttpStatus.BAD_REQUEST, "잘못된 일반 타이머 이벤트 데이터입니다"), + INVALID_TIME_BASED_TIMER_EVENT_DATA(HttpStatus.BAD_REQUEST, "잘못된 자유토론 타이머 이벤트 데이터입니다"), + INVALID_TIMER_EVENT(HttpStatus.BAD_REQUEST, "잘못된 타이머 이벤트 데이터입니다"), + ; private final HttpStatus status; private final String message; diff --git a/src/main/java/com/debatetimer/service/sharing/SharingService.java b/src/main/java/com/debatetimer/service/sharing/SharingService.java index 1fcedb4d..8002052f 100644 --- a/src/main/java/com/debatetimer/service/sharing/SharingService.java +++ b/src/main/java/com/debatetimer/service/sharing/SharingService.java @@ -1,19 +1,21 @@ package com.debatetimer.service.sharing; +import com.debatetimer.domain.sharing.TimerEvent; import com.debatetimer.dto.sharing.request.SharingRequest; import com.debatetimer.dto.sharing.response.SharingResponse; -import com.debatetimer.dto.sharing.response.TimerEventInfoResponse; +import com.debatetimer.dto.sharing.response.TimerEventDataResponse; +import java.util.Optional; import org.springframework.stereotype.Service; @Service public class SharingService { public SharingResponse share(SharingRequest request) { - - return request.toTimerEventInfo() - .map(eventInfo -> new SharingResponse( + TimerEvent timerEvent = request.toTimerEvent(); + return Optional.ofNullable(timerEvent.getTimerEventData()) + .map(eventData -> new SharingResponse( request.eventType(), - new TimerEventInfoResponse(eventInfo) + new TimerEventDataResponse(eventData) )) .orElse(new SharingResponse(request.eventType(), null)); } diff --git a/src/test/java/com/debatetimer/domain/sharing/TimerEventInfoTest.java b/src/test/java/com/debatetimer/domain/sharing/TimerEventDataTest.java similarity index 85% rename from src/test/java/com/debatetimer/domain/sharing/TimerEventInfoTest.java rename to src/test/java/com/debatetimer/domain/sharing/TimerEventDataTest.java index 8a6cd764..1811b00e 100644 --- a/src/test/java/com/debatetimer/domain/sharing/TimerEventInfoTest.java +++ b/src/test/java/com/debatetimer/domain/sharing/TimerEventDataTest.java @@ -9,31 +9,31 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -class TimerEventInfoTest { +class TimerEventDataTest { @Nested class ValidateCurrentTeam { @Test void 일반_타이머의_경우_현재_발언팀이_입력되면_안된다() { - assertThatThrownBy(() -> new TimerEventInfo( + assertThatThrownBy(() -> new TimerEventData( CustomizeBoxType.NORMAL, 2, Stance.CONS, 30L )).isInstanceOf(DTClientErrorException.class) - .hasMessage(ClientErrorCode.INVALID_NORMAL_TIMER_EVENT_INFO.getMessage()); + .hasMessage(ClientErrorCode.INVALID_NORMAL_TIMER_EVENT_DATA.getMessage()); } @Test void 자유토론_타이머의_경우_현재_발언팀이_입력되어야_한다() { - assertThatThrownBy(() -> new TimerEventInfo( + assertThatThrownBy(() -> new TimerEventData( CustomizeBoxType.TIME_BASED, 2, null, 30L )).isInstanceOf(DTClientErrorException.class) - .hasMessage(ClientErrorCode.INVALID_TIME_BASED_TIMER_EVENT_INFO.getMessage()); + .hasMessage(ClientErrorCode.INVALID_TIME_BASED_TIMER_EVENT_DATA.getMessage()); } } } From 46c6cbaff7869361e39b716bf7fcfba4687bdb5e Mon Sep 17 00:00:00 2001 From: coli Date: Mon, 30 Mar 2026 19:11:02 +0900 Subject: [PATCH 14/15] =?UTF-8?q?feat:=20event=EB=B3=84=20=EA=B2=80?= =?UTF-8?q?=EC=A6=9D=EB=A1=9C=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/sharing/TimerEventTypeTest.java | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 src/test/java/com/debatetimer/domain/sharing/TimerEventTypeTest.java diff --git a/src/test/java/com/debatetimer/domain/sharing/TimerEventTypeTest.java b/src/test/java/com/debatetimer/domain/sharing/TimerEventTypeTest.java new file mode 100644 index 00000000..b080c112 --- /dev/null +++ b/src/test/java/com/debatetimer/domain/sharing/TimerEventTypeTest.java @@ -0,0 +1,50 @@ +package com.debatetimer.domain.sharing; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import com.debatetimer.domain.customize.CustomizeBoxType; +import com.debatetimer.exception.custom.DTClientErrorException; +import com.debatetimer.exception.errorcode.ClientErrorCode; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; + +class TimerEventTypeTest { + + @Nested + class ValidateData { + + @EnumSource( + value = TimerEventType.class, + names = { + "NEXT", + "BEFORE", + "STOP", + "PLAY", + "RESET", + "TEAM_SWITCH", + } + ) + @ParameterizedTest + void 타이머_이벤트_데이터가_존재하여야_한다(TimerEventType eventType) { + assertThatThrownBy(() -> eventType.validateEventData(null)) + .isInstanceOf(DTClientErrorException.class) + .hasMessage(ClientErrorCode.INVALID_TIMER_EVENT.getMessage()); + + } + + @EnumSource(value = TimerEventType.class, names = {"FINISHED"}) + @ParameterizedTest + void 타이머_이벤트_데이터가_존재하지_않아야_한다(TimerEventType eventType) { + TimerEventData timerEventData = new TimerEventData( + CustomizeBoxType.NORMAL, + 2, + null, + 30L + ); + assertThatThrownBy(() -> eventType.validateEventData(timerEventData)) + .isInstanceOf(DTClientErrorException.class) + .hasMessage(ClientErrorCode.INVALID_TIMER_EVENT.getMessage()); + } + } +} From c197ad58ffc61339be492efabdc6d5eca119446a Mon Sep 17 00:00:00 2001 From: coli Date: Mon, 30 Mar 2026 19:21:15 +0900 Subject: [PATCH 15/15] =?UTF-8?q?feat:=20=EC=83=9D=EC=84=B1=EC=9E=90=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/debatetimer/domain/sharing/TimerEvent.java | 4 ++++ .../debatetimer/dto/sharing/request/SharingRequest.java | 8 +------- .../controller/sharing/SharingControllerTest.java | 1 + 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/debatetimer/domain/sharing/TimerEvent.java b/src/main/java/com/debatetimer/domain/sharing/TimerEvent.java index c38b0da7..e32a9a20 100644 --- a/src/main/java/com/debatetimer/domain/sharing/TimerEvent.java +++ b/src/main/java/com/debatetimer/domain/sharing/TimerEvent.java @@ -21,4 +21,8 @@ public TimerEvent( this.eventType = eventType; this.timerEventData = timerEventData; } + + public TimerEvent(TimerEventType eventType) { + this(eventType, null); + } } diff --git a/src/main/java/com/debatetimer/dto/sharing/request/SharingRequest.java b/src/main/java/com/debatetimer/dto/sharing/request/SharingRequest.java index fd68faf4..dab8299a 100644 --- a/src/main/java/com/debatetimer/dto/sharing/request/SharingRequest.java +++ b/src/main/java/com/debatetimer/dto/sharing/request/SharingRequest.java @@ -1,7 +1,6 @@ package com.debatetimer.dto.sharing.request; import com.debatetimer.domain.sharing.TimerEvent; -import com.debatetimer.domain.sharing.TimerEventData; import com.debatetimer.domain.sharing.TimerEventType; import jakarta.annotation.Nullable; import jakarta.validation.Valid; @@ -21,11 +20,6 @@ public TimerEvent toTimerEvent() { return Optional.ofNullable(data) .map(TimerEventInfoRequest::toTimerEventInfo) .map(eventData -> new TimerEvent(eventType, eventData)) - .orElse(new TimerEvent(eventType, null)); - } - - public Optional toTimerEventInfo() { - return Optional.ofNullable(data) - .map(TimerEventInfoRequest::toTimerEventInfo); + .orElseGet(() -> new TimerEvent(eventType)); } } diff --git a/src/test/java/com/debatetimer/controller/sharing/SharingControllerTest.java b/src/test/java/com/debatetimer/controller/sharing/SharingControllerTest.java index 5ae95913..d644f907 100644 --- a/src/test/java/com/debatetimer/controller/sharing/SharingControllerTest.java +++ b/src/test/java/com/debatetimer/controller/sharing/SharingControllerTest.java @@ -50,6 +50,7 @@ class Share { assertAll( () -> assertThat(response.eventType()).isEqualTo(request.eventType()), + () -> assertThat(response.data()).isNotNull(), () -> assertThat(response.data().timerType()).isEqualTo(request.data().timerType()), () -> assertThat(response.data().sequence()).isEqualTo(request.data().sequence()), () -> assertThat(response.data().currentTeam()).isEqualTo(request.data().currentTeam()),