From a840625a33b273ed4df6e953dada57281358f1fc Mon Sep 17 00:00:00 2001 From: coli Date: Tue, 14 Apr 2026 03:22:02 +0900 Subject: [PATCH 01/14] =?UTF-8?q?chore:=20=EC=9B=B9=EC=86=8C=EC=BC=93=20?= =?UTF-8?q?=ED=95=98=ED=8A=B8=EB=B9=84=ED=8A=B8=20=EC=84=A4=EC=A0=95=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../config/sharing/WebSocketConfig.java | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/debatetimer/config/sharing/WebSocketConfig.java b/src/main/java/com/debatetimer/config/sharing/WebSocketConfig.java index b2ee31a6..aeb9c819 100644 --- a/src/main/java/com/debatetimer/config/sharing/WebSocketConfig.java +++ b/src/main/java/com/debatetimer/config/sharing/WebSocketConfig.java @@ -1,11 +1,14 @@ package com.debatetimer.config.sharing; import com.debatetimer.config.CorsProperties; +import java.time.Duration; import java.util.List; import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolver; import org.springframework.messaging.simp.config.MessageBrokerRegistry; +import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker; import org.springframework.web.socket.config.annotation.StompEndpointRegistry; import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer; @@ -15,6 +18,12 @@ @EnableWebSocketMessageBroker public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { + private static final long SERVER_TO_CLIENT_HEARTBEAT_DURATION = Duration.ofSeconds(10).toMillis(); + private static final long CLIENT_TO_SERVER_HEARTBEAT_DURATION = Duration.ofSeconds(10).toMillis(); + private static final long SOCKJS_HEART_BEAT_DURATION = Duration.ofSeconds(10).toMillis(); + private static final String HEART_BEAT_THREAD_PREFIX = "wss-heartbeat-"; + private static final int HEART_BEAT_THREAD_COUNT = 1; + private final CorsProperties corsProperties; private final WebSocketAuthMemberResolver webSocketAuthMemberResolver; @@ -25,7 +34,9 @@ public void addArgumentResolvers(List resolvers) @Override public void configureMessageBroker(MessageBrokerRegistry registry) { - registry.enableSimpleBroker("/room", "/chairman"); + registry.enableSimpleBroker("/room", "/chairman") + .setHeartbeatValue(new long[]{SERVER_TO_CLIENT_HEARTBEAT_DURATION, CLIENT_TO_SERVER_HEARTBEAT_DURATION}) + .setTaskScheduler(heartBeatScheduler()); registry.setApplicationDestinationPrefixes("/app"); } @@ -33,6 +44,16 @@ public void configureMessageBroker(MessageBrokerRegistry registry) { public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/ws") .setAllowedOriginPatterns(corsProperties.getCorsOrigin()) - .withSockJS(); + .withSockJS() + .setHeartbeatTime(SOCKJS_HEART_BEAT_DURATION); + } + + @Bean + public ThreadPoolTaskScheduler heartBeatScheduler() { + ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); + scheduler.setPoolSize(HEART_BEAT_THREAD_COUNT); + scheduler.setThreadNamePrefix(HEART_BEAT_THREAD_PREFIX); + scheduler.initialize(); + return scheduler; } } From c4a088f4dceab0eb9e2cfd88debbd2b46b8012ca Mon Sep 17 00:00:00 2001 From: coli Date: Tue, 14 Apr 2026 03:46:02 +0900 Subject: [PATCH 02/14] =?UTF-8?q?chore:=20sharing=20=EC=BB=A8=ED=8A=B8?= =?UTF-8?q?=EB=A1=A4=EB=9F=AC=20=EB=A6=AC=EB=84=A4=EC=9D=B4=EB=B0=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../{SharingController.java => SharingWebSocketController.java} | 2 +- ...gControllerTest.java => SharingWebSocketControllerTest.java} | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename src/main/java/com/debatetimer/controller/sharing/{SharingController.java => SharingWebSocketController.java} (95%) rename src/test/java/com/debatetimer/controller/sharing/{SharingControllerTest.java => SharingWebSocketControllerTest.java} (98%) diff --git a/src/main/java/com/debatetimer/controller/sharing/SharingController.java b/src/main/java/com/debatetimer/controller/sharing/SharingWebSocketController.java similarity index 95% rename from src/main/java/com/debatetimer/controller/sharing/SharingController.java rename to src/main/java/com/debatetimer/controller/sharing/SharingWebSocketController.java index 0216a15b..20bc794a 100644 --- a/src/main/java/com/debatetimer/controller/sharing/SharingController.java +++ b/src/main/java/com/debatetimer/controller/sharing/SharingWebSocketController.java @@ -13,7 +13,7 @@ @Controller @RequiredArgsConstructor -public class SharingController { +public class SharingWebSocketController { private final SharingService sharingService; diff --git a/src/test/java/com/debatetimer/controller/sharing/SharingControllerTest.java b/src/test/java/com/debatetimer/controller/sharing/SharingWebSocketControllerTest.java similarity index 98% rename from src/test/java/com/debatetimer/controller/sharing/SharingControllerTest.java rename to src/test/java/com/debatetimer/controller/sharing/SharingWebSocketControllerTest.java index d644f907..2c96ebc5 100644 --- a/src/test/java/com/debatetimer/controller/sharing/SharingControllerTest.java +++ b/src/test/java/com/debatetimer/controller/sharing/SharingWebSocketControllerTest.java @@ -21,7 +21,7 @@ import org.junit.jupiter.params.provider.NullSource; import org.springframework.messaging.simp.stomp.StompHeaders; -class SharingControllerTest extends BaseStompTest { +class SharingWebSocketControllerTest extends BaseStompTest { @Nested class Share { From 53dfa1a83e15aba71a13f654696f75ce53f804bd Mon Sep 17 00:00:00 2001 From: coli Date: Tue, 14 Apr 2026 04:04:47 +0900 Subject: [PATCH 03/14] =?UTF-8?q?feat:=20=EC=82=AC=ED=9A=8C=EC=9E=90=20?= =?UTF-8?q?=ED=86=A0=ED=81=B0=20=EB=B0=9C=EA=B8=89=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EA=B0=9C=EB=B0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sharing/SharingRestController.java | 25 +++++++++++++++++++ .../controller/tool/jwt/JwtTokenProvider.java | 4 +++ .../controller/tool/jwt/TokenType.java | 3 ++- .../CustomizeTableDomainRepository.java | 5 ++++ .../response/ChairmanTokenResponse.java | 7 ++++++ .../customize/CustomizeTimeBoxRepository.java | 2 ++ .../service/sharing/SharingService.java | 18 +++++++++++++ 7 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/debatetimer/controller/sharing/SharingRestController.java create mode 100644 src/main/java/com/debatetimer/dto/sharing/response/ChairmanTokenResponse.java diff --git a/src/main/java/com/debatetimer/controller/sharing/SharingRestController.java b/src/main/java/com/debatetimer/controller/sharing/SharingRestController.java new file mode 100644 index 00000000..7af73c6b --- /dev/null +++ b/src/main/java/com/debatetimer/controller/sharing/SharingRestController.java @@ -0,0 +1,25 @@ +package com.debatetimer.controller.sharing; + +import com.debatetimer.controller.auth.AuthMember; +import com.debatetimer.domain.member.Member; +import com.debatetimer.dto.sharing.response.ChairmanTokenResponse; +import com.debatetimer.service.sharing.SharingService; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequiredArgsConstructor +public class SharingRestController { + + private final SharingService sharingService; + + @GetMapping("/api/share/{tableId}/chairman-token") + public ChairmanTokenResponse publishChairmanToken( + @AuthMember Member member, + @PathVariable("tableId") long tableId + ) { + return sharingService.issueChairmanToken(tableId, member); + } +} diff --git a/src/main/java/com/debatetimer/controller/tool/jwt/JwtTokenProvider.java b/src/main/java/com/debatetimer/controller/tool/jwt/JwtTokenProvider.java index ffd28bca..9f3ef75b 100644 --- a/src/main/java/com/debatetimer/controller/tool/jwt/JwtTokenProvider.java +++ b/src/main/java/com/debatetimer/controller/tool/jwt/JwtTokenProvider.java @@ -23,6 +23,10 @@ public String createRefreshToken(MemberInfo memberInfo) { return createToken(memberInfo, refreshTokenExpiration, TokenType.REFRESH_TOKEN); } + public String createChairmanToken(MemberInfo memberInfo, long expirationSeconds) { + return createToken(memberInfo, Duration.ofSeconds(expirationSeconds), TokenType.CHAIRMAN_TOKEN); + } + private String createToken(MemberInfo memberInfo, Duration expiration, TokenType tokenType) { Date now = new Date(); Date expiredDate = new Date(now.getTime() + expiration.toMillis()); diff --git a/src/main/java/com/debatetimer/controller/tool/jwt/TokenType.java b/src/main/java/com/debatetimer/controller/tool/jwt/TokenType.java index 1112e4b9..9d3a4d0c 100644 --- a/src/main/java/com/debatetimer/controller/tool/jwt/TokenType.java +++ b/src/main/java/com/debatetimer/controller/tool/jwt/TokenType.java @@ -3,5 +3,6 @@ public enum TokenType { ACCESS_TOKEN, - REFRESH_TOKEN + REFRESH_TOKEN, + CHAIRMAN_TOKEN } diff --git a/src/main/java/com/debatetimer/domainrepository/customize/CustomizeTableDomainRepository.java b/src/main/java/com/debatetimer/domainrepository/customize/CustomizeTableDomainRepository.java index 2c2e96e7..0132389d 100644 --- a/src/main/java/com/debatetimer/domainrepository/customize/CustomizeTableDomainRepository.java +++ b/src/main/java/com/debatetimer/domainrepository/customize/CustomizeTableDomainRepository.java @@ -61,6 +61,11 @@ public List getCustomizeTimeBoxes(long tableId, Member member) return toCustomizeTimeBoxes(timeBoxEntityList, bellEntityList); } + @Transactional(readOnly = true) + public long getTotalTimeBoxTimes(long tableId) { + return timeBoxRepository.sumTimeByTableId(tableId); + } + private List toCustomizeTimeBoxes( List timeBoxEntities, List bellEntities diff --git a/src/main/java/com/debatetimer/dto/sharing/response/ChairmanTokenResponse.java b/src/main/java/com/debatetimer/dto/sharing/response/ChairmanTokenResponse.java new file mode 100644 index 00000000..c10fc79e --- /dev/null +++ b/src/main/java/com/debatetimer/dto/sharing/response/ChairmanTokenResponse.java @@ -0,0 +1,7 @@ +package com.debatetimer.dto.sharing.response; + +public record ChairmanTokenResponse( + String chairmanToken +) { + +} diff --git a/src/main/java/com/debatetimer/repository/customize/CustomizeTimeBoxRepository.java b/src/main/java/com/debatetimer/repository/customize/CustomizeTimeBoxRepository.java index 1a0e524d..80ecdcbb 100644 --- a/src/main/java/com/debatetimer/repository/customize/CustomizeTimeBoxRepository.java +++ b/src/main/java/com/debatetimer/repository/customize/CustomizeTimeBoxRepository.java @@ -13,6 +13,8 @@ public interface CustomizeTimeBoxRepository extends Repository findAllByCustomizeTable(CustomizeTableEntity table); + long sumTimeByTableId(long tableId); + @Query("DELETE FROM CustomizeTimeBoxEntity ctb WHERE ctb.customizeTable.id = :tableId") @Modifying(clearAutomatically = true, flushAutomatically = true) void deleteAllByTable(long tableId); diff --git a/src/main/java/com/debatetimer/service/sharing/SharingService.java b/src/main/java/com/debatetimer/service/sharing/SharingService.java index 8002052f..11490a26 100644 --- a/src/main/java/com/debatetimer/service/sharing/SharingService.java +++ b/src/main/java/com/debatetimer/service/sharing/SharingService.java @@ -1,15 +1,26 @@ package com.debatetimer.service.sharing; +import com.debatetimer.controller.tool.jwt.JwtTokenProvider; +import com.debatetimer.domain.customize.CustomizeTable; +import com.debatetimer.domain.member.Member; import com.debatetimer.domain.sharing.TimerEvent; +import com.debatetimer.domainrepository.customize.CustomizeTableDomainRepository; +import com.debatetimer.dto.member.MemberInfo; import com.debatetimer.dto.sharing.request.SharingRequest; +import com.debatetimer.dto.sharing.response.ChairmanTokenResponse; import com.debatetimer.dto.sharing.response.SharingResponse; import com.debatetimer.dto.sharing.response.TimerEventDataResponse; import java.util.Optional; +import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @Service +@RequiredArgsConstructor public class SharingService { + private final JwtTokenProvider jwtTokenProvider; + private final CustomizeTableDomainRepository customizeTableDomainRepository; + public SharingResponse share(SharingRequest request) { TimerEvent timerEvent = request.toTimerEvent(); return Optional.ofNullable(timerEvent.getTimerEventData()) @@ -19,4 +30,11 @@ public SharingResponse share(SharingRequest request) { )) .orElse(new SharingResponse(request.eventType(), null)); } + + public ChairmanTokenResponse issueChairmanToken(long tableId, Member member) { + CustomizeTable customizeTable = customizeTableDomainRepository.getByIdAndMember(tableId, member); + long debateTime = customizeTableDomainRepository.getTotalTimeBoxTimes(customizeTable.getId()); + String chairmanToken = jwtTokenProvider.createChairmanToken(new MemberInfo(member), debateTime * 2); + return new ChairmanTokenResponse(chairmanToken); + } } From 0a75ec1297b03b4d191eef744db5fc205b73b03a Mon Sep 17 00:00:00 2001 From: coli Date: Tue, 14 Apr 2026 04:10:56 +0900 Subject: [PATCH 04/14] =?UTF-8?q?test:=20=EB=A0=88=ED=8F=AC=EC=A7=80?= =?UTF-8?q?=ED=86=A0=EB=A6=AC=20=EC=BF=BC=EB=A6=AC=20=EA=B2=80=EC=A6=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../customize/CustomizeTimeBoxRepository.java | 1 + .../CustomizeTimeBoxRepositoryTest.java | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/src/main/java/com/debatetimer/repository/customize/CustomizeTimeBoxRepository.java b/src/main/java/com/debatetimer/repository/customize/CustomizeTimeBoxRepository.java index 80ecdcbb..89d32ade 100644 --- a/src/main/java/com/debatetimer/repository/customize/CustomizeTimeBoxRepository.java +++ b/src/main/java/com/debatetimer/repository/customize/CustomizeTimeBoxRepository.java @@ -13,6 +13,7 @@ public interface CustomizeTimeBoxRepository extends Repository findAllByCustomizeTable(CustomizeTableEntity table); + @Query("SELECT SUM(ctb.time) FROM CustomizeTimeBoxEntity ctb WHERE ctb.customizeTable.id = :tableId") long sumTimeByTableId(long tableId); @Query("DELETE FROM CustomizeTimeBoxEntity ctb WHERE ctb.customizeTable.id = :tableId") diff --git a/src/test/java/com/debatetimer/repository/customize/CustomizeTimeBoxRepositoryTest.java b/src/test/java/com/debatetimer/repository/customize/CustomizeTimeBoxRepositoryTest.java index 5fcf6b39..93268c2d 100644 --- a/src/test/java/com/debatetimer/repository/customize/CustomizeTimeBoxRepositoryTest.java +++ b/src/test/java/com/debatetimer/repository/customize/CustomizeTimeBoxRepositoryTest.java @@ -80,4 +80,22 @@ class DeleteAllByTable { .doesNotThrowAnyException(); } } + + @Nested + class SumTimeByTableId { + + @Test + void 특정_테이블의_타임_박스시간의_합을_반환한다() { + Member chan = memberGenerator.generate("default@gmail.com"); + CustomizeTableEntity debateTable = customizeTableEntityGenerator.generate(chan); + CustomizeTimeBoxEntity timeBox1 = customizeTimeBoxEntityGenerator.generate(debateTable, + CustomizeBoxType.NORMAL, 1, 10); + CustomizeTimeBoxEntity timeBox2 = customizeTimeBoxEntityGenerator.generate(debateTable, + CustomizeBoxType.NORMAL, 2, 20); + + long summedTimeByTableId = customizeTimeBoxRepository.sumTimeByTableId(debateTable.getId()); + + assertThat(summedTimeByTableId).isEqualTo(timeBox1.getTime() + timeBox2.getTime()); + } + } } From a12dd9100355885e3e8273b49374daf3bb5490ea Mon Sep 17 00:00:00 2001 From: coli Date: Tue, 14 Apr 2026 04:18:10 +0900 Subject: [PATCH 05/14] =?UTF-8?q?test:=20=ED=86=A0=ED=81=B0=20=EB=B0=9C?= =?UTF-8?q?=ED=96=89=20=EB=A1=9C=EC=A7=81=20=EA=B2=80=EC=A6=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/sharing/SharingServiceTest.java | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 src/test/java/com/debatetimer/service/sharing/SharingServiceTest.java diff --git a/src/test/java/com/debatetimer/service/sharing/SharingServiceTest.java b/src/test/java/com/debatetimer/service/sharing/SharingServiceTest.java new file mode 100644 index 00000000..56a1a54a --- /dev/null +++ b/src/test/java/com/debatetimer/service/sharing/SharingServiceTest.java @@ -0,0 +1,44 @@ +package com.debatetimer.service.sharing; + +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import com.debatetimer.domain.customize.CustomizeBoxType; +import com.debatetimer.domain.member.Member; +import com.debatetimer.entity.customize.CustomizeTableEntity; +import com.debatetimer.exception.custom.DTClientErrorException; +import com.debatetimer.exception.errorcode.ClientErrorCode; +import com.debatetimer.service.BaseServiceTest; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; + +class SharingServiceTest extends BaseServiceTest { + + @Autowired + private SharingService sharingService; + + @Nested + class IssueChairmanToken { + + @Test + void 사회자_토큰을_할당한다() { + Member member = memberGenerator.generate("email@email.com"); + CustomizeTableEntity tableEntity = customizeTableEntityGenerator.generate(member); + customizeTimeBoxEntityGenerator.generate(tableEntity, CustomizeBoxType.NORMAL, 1); + customizeTimeBoxEntityGenerator.generate(tableEntity, CustomizeBoxType.NORMAL, 2); + + assertThatCode(() -> sharingService.issueChairmanToken(tableEntity.getId(), member)) + .doesNotThrowAnyException(); + } + + @Test + void 회원_소유의_테이블이_아니면_에러가_발생한다() { + Member member = memberGenerator.generate("email@email.com"); + + assertThatThrownBy(() -> sharingService.issueChairmanToken(1L, member)) + .isInstanceOf(DTClientErrorException.class) + .hasMessage(ClientErrorCode.TABLE_NOT_FOUND.getMessage()); + } + } +} From 9ab2d02ec97530581a2e5c0be0ed68736572549d Mon Sep 17 00:00:00 2001 From: coli Date: Tue, 14 Apr 2026 04:31:59 +0900 Subject: [PATCH 06/14] =?UTF-8?q?test:=20=EB=AC=B8=EC=84=9C=ED=99=94=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sharing/SharingRestController.java | 2 +- .../controller/BaseDocumentTest.java | 4 ++ .../java/com/debatetimer/controller/Tag.java | 1 + .../sharing/SharingDocumentTest.java | 59 +++++++++++++++++++ 4 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 src/test/java/com/debatetimer/controller/sharing/SharingDocumentTest.java diff --git a/src/main/java/com/debatetimer/controller/sharing/SharingRestController.java b/src/main/java/com/debatetimer/controller/sharing/SharingRestController.java index 7af73c6b..3231df17 100644 --- a/src/main/java/com/debatetimer/controller/sharing/SharingRestController.java +++ b/src/main/java/com/debatetimer/controller/sharing/SharingRestController.java @@ -16,7 +16,7 @@ public class SharingRestController { private final SharingService sharingService; @GetMapping("/api/share/{tableId}/chairman-token") - public ChairmanTokenResponse publishChairmanToken( + public ChairmanTokenResponse issueChairmanToken( @AuthMember Member member, @PathVariable("tableId") long tableId ) { diff --git a/src/test/java/com/debatetimer/controller/BaseDocumentTest.java b/src/test/java/com/debatetimer/controller/BaseDocumentTest.java index bbac2b81..3c139034 100644 --- a/src/test/java/com/debatetimer/controller/BaseDocumentTest.java +++ b/src/test/java/com/debatetimer/controller/BaseDocumentTest.java @@ -15,6 +15,7 @@ import com.debatetimer.service.organization.OrganizationService; import com.debatetimer.service.poll.PollService; import com.debatetimer.service.poll.VoteService; +import com.debatetimer.service.sharing.SharingService; import io.restassured.RestAssured; import io.restassured.builder.RequestSpecBuilder; import io.restassured.filter.log.RequestLoggingFilter; @@ -71,6 +72,9 @@ public abstract class BaseDocumentTest { @MockitoBean protected VoteService voteService; + @MockitoBean + protected SharingService sharingService; + @MockitoBean protected OrganizationService organizationService; diff --git a/src/test/java/com/debatetimer/controller/Tag.java b/src/test/java/com/debatetimer/controller/Tag.java index 5da09bb2..12ac3339 100644 --- a/src/test/java/com/debatetimer/controller/Tag.java +++ b/src/test/java/com/debatetimer/controller/Tag.java @@ -6,6 +6,7 @@ public enum Tag { PARLIAMENTARY_API("Parliamentary Table API"), TIME_BASED_API("Time Based Table API"), CUSTOMIZE_API("Customize Table API"), + SHARING_API("Sharing API"), POLL_API("Poll API"), ORGANIZATION_API("Organization API"); diff --git a/src/test/java/com/debatetimer/controller/sharing/SharingDocumentTest.java b/src/test/java/com/debatetimer/controller/sharing/SharingDocumentTest.java new file mode 100644 index 00000000..ef87c825 --- /dev/null +++ b/src/test/java/com/debatetimer/controller/sharing/SharingDocumentTest.java @@ -0,0 +1,59 @@ +package com.debatetimer.controller.sharing; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.springframework.restdocs.headers.HeaderDocumentation.headerWithName; +import static org.springframework.restdocs.payload.JsonFieldType.STRING; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; + +import com.debatetimer.controller.BaseDocumentTest; +import com.debatetimer.controller.RestDocumentationRequest; +import com.debatetimer.controller.RestDocumentationResponse; +import com.debatetimer.controller.Tag; +import com.debatetimer.domain.member.Member; +import com.debatetimer.dto.sharing.response.ChairmanTokenResponse; +import io.restassured.http.ContentType; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.http.HttpHeaders; + +public class SharingDocumentTest extends BaseDocumentTest { + + + @Nested + class IssueChairmanToken { + + private final RestDocumentationRequest requestDocument = request() + .tag(Tag.SHARING_API) + .summary("사회자용 토큰 발급") + .requestHeader(headerWithName(HttpHeaders.AUTHORIZATION).description("액세스 토큰")) + .pathParameter(parameterWithName("tableId").description("테이블 id")); + + private final RestDocumentationResponse responseDocument = response() + .responseBodyField( + fieldWithPath("chairmanToken").type(STRING).description("사회자용 토큰") + ); + + @Test + void 사회자_용_토큰_생성_성공() { + long requestTableId = 1L; + ChairmanTokenResponse chairmanTokenResponse = new ChairmanTokenResponse("testToken"); + doReturn(chairmanTokenResponse).when(sharingService) + .issueChairmanToken(eq(requestTableId), any(Member.class)); + + var document = document("sharing/get", 200) + .request(requestDocument) + .response(responseDocument) + .build(); + + given(document) + .contentType(ContentType.JSON) + .headers(EXIST_MEMBER_HEADER) + .pathParam("tableId", String.valueOf(requestTableId)) + .when().get("/api/share/{tableId}/chairman-token") + .then().statusCode(200); + } + } +} From 2eca3d839cd0aa4b1d5d11ef046ac5ebe1f229a9 Mon Sep 17 00:00:00 2001 From: coli Date: Tue, 14 Apr 2026 04:42:42 +0900 Subject: [PATCH 07/14] =?UTF-8?q?test:=20=EC=82=AC=ED=9A=8C=EC=9E=90=20?= =?UTF-8?q?=EA=B2=80=EC=A6=9D=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sharing/WebSocketAuthMemberResolver.java | 2 +- .../sharing/SharingWebSocketController.java | 3 ++ .../controller/tool/jwt/AuthManager.java | 4 +++ .../controller/tool/jwt/JwtTokenResolver.java | 4 +++ .../SharingWebSocketControllerTest.java | 28 +++++++++++++++++-- .../debatetimer/fixture/HeaderGenerator.java | 6 ++-- 6 files changed, 40 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/debatetimer/config/sharing/WebSocketAuthMemberResolver.java b/src/main/java/com/debatetimer/config/sharing/WebSocketAuthMemberResolver.java index de16ac9f..19c76364 100644 --- a/src/main/java/com/debatetimer/config/sharing/WebSocketAuthMemberResolver.java +++ b/src/main/java/com/debatetimer/config/sharing/WebSocketAuthMemberResolver.java @@ -34,7 +34,7 @@ public Object resolveArgument(MethodParameter parameter, Message message) { throw new DTClientErrorException(ClientErrorCode.UNAUTHORIZED_MEMBER); } - String email = authManager.resolveAccessToken(token); + String email = authManager.resolveChairmanToken(token); return authService.getMember(email); } } diff --git a/src/main/java/com/debatetimer/controller/sharing/SharingWebSocketController.java b/src/main/java/com/debatetimer/controller/sharing/SharingWebSocketController.java index 20bc794a..c2ba0479 100644 --- a/src/main/java/com/debatetimer/controller/sharing/SharingWebSocketController.java +++ b/src/main/java/com/debatetimer/controller/sharing/SharingWebSocketController.java @@ -1,5 +1,7 @@ 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 com.debatetimer.service.sharing.SharingService; @@ -20,6 +22,7 @@ public class SharingWebSocketController { @MessageMapping("/event/{roomId}") @SendTo("/room/{roomId}") public SharingResponse share( + @AuthMember Member member, @DestinationVariable(value = "roomId") long roomId, @Valid @Payload SharingRequest request ) { diff --git a/src/main/java/com/debatetimer/controller/tool/jwt/AuthManager.java b/src/main/java/com/debatetimer/controller/tool/jwt/AuthManager.java index a614224f..2a6e2a51 100644 --- a/src/main/java/com/debatetimer/controller/tool/jwt/AuthManager.java +++ b/src/main/java/com/debatetimer/controller/tool/jwt/AuthManager.java @@ -37,4 +37,8 @@ public String resolveAccessToken(String accessToken) { public String resolveRefreshToken(String refreshToken) { return jwtTokenResolver.resolveRefreshToken(refreshToken); } + + public String resolveChairmanToken(String chairmanToken) { + return jwtTokenResolver.resolveAccessToken(chairmanToken); + } } diff --git a/src/main/java/com/debatetimer/controller/tool/jwt/JwtTokenResolver.java b/src/main/java/com/debatetimer/controller/tool/jwt/JwtTokenResolver.java index de5d33f7..15e0d186 100644 --- a/src/main/java/com/debatetimer/controller/tool/jwt/JwtTokenResolver.java +++ b/src/main/java/com/debatetimer/controller/tool/jwt/JwtTokenResolver.java @@ -23,6 +23,10 @@ public String resolveRefreshToken(String refreshToken) { return resolveToken(refreshToken, TokenType.REFRESH_TOKEN); } + public String resolveChairmanToken(String chairmanToken) { + return resolveToken(chairmanToken, TokenType.CHAIRMAN_TOKEN); + } + private String resolveToken(String token, TokenType tokenType) { try { Claims claims = Jwts.parserBuilder() diff --git a/src/test/java/com/debatetimer/controller/sharing/SharingWebSocketControllerTest.java b/src/test/java/com/debatetimer/controller/sharing/SharingWebSocketControllerTest.java index 2c96ebc5..88775492 100644 --- a/src/test/java/com/debatetimer/controller/sharing/SharingWebSocketControllerTest.java +++ b/src/test/java/com/debatetimer/controller/sharing/SharingWebSocketControllerTest.java @@ -31,7 +31,7 @@ class Share { long roomId = 1L; MessageFrameHandler handler = new MessageFrameHandler<>(SharingResponse.class); Member member = memberGenerator.generate("example@email.com"); - StompHeaders headers = headerGenerator.generateAccessTokenHeader("/app/event/" + roomId, member); + StompHeaders headers = headerGenerator.generateChairmanTokenHeader("/app/event/" + roomId, member); SharingRequest request = new SharingRequest( TimerEventType.NEXT, new TimerEventInfoRequest( @@ -58,12 +58,34 @@ class Share { ); } + @Test + void 사회자가_아니면_이벤트를_발행할_수_없다() throws ExecutionException, InterruptedException, TimeoutException { + long roomId = 1L; + MessageFrameHandler handler = new MessageFrameHandler<>(SharingResponse.class); + Member member = memberGenerator.generate("example@email.com"); + SharingRequest request = new SharingRequest( + TimerEventType.NEXT, + new TimerEventInfoRequest( + CustomizeBoxType.NORMAL, + null, + 2, + 30 + ) + ); + stompSession.subscribe("/room/" + roomId, handler); //청중의 구독 + stompSession.send("/app/event/" + roomId, request); //사회자의 이벤트 발생 + + assertThatThrownBy(() -> handler.getCompletableFuture() + .get(2L, TimeUnit.SECONDS)) + .isInstanceOf(TimeoutException.class); + } + @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); + StompHeaders headers = headerGenerator.generateChairmanTokenHeader("/app/event/" + roomId, member); SharingRequest request = new SharingRequest(TimerEventType.FINISHED, null); stompSession.subscribe("/room/" + roomId, handler); //청중의 구독 @@ -84,7 +106,7 @@ class Share { long roomId = 1L; MessageFrameHandler handler = new MessageFrameHandler<>(SharingResponse.class); Member member = memberGenerator.generate("example@email.com"); - StompHeaders headers = headerGenerator.generateAccessTokenHeader("/app/event/" + roomId, member); + StompHeaders headers = headerGenerator.generateChairmanTokenHeader("/app/event/" + roomId, member); SharingRequest request = new SharingRequest( TimerEventType.NEXT, new TimerEventInfoRequest( diff --git a/src/test/java/com/debatetimer/fixture/HeaderGenerator.java b/src/test/java/com/debatetimer/fixture/HeaderGenerator.java index 70362980..5a76eaac 100644 --- a/src/test/java/com/debatetimer/fixture/HeaderGenerator.java +++ b/src/test/java/com/debatetimer/fixture/HeaderGenerator.java @@ -23,11 +23,11 @@ public Headers generateAccessTokenHeader(Member member) { return new Headers(new Header(HttpHeaders.AUTHORIZATION, accessToken)); } - public StompHeaders generateAccessTokenHeader(String destination, Member member) { - String accessToken = jwtTokenProvider.createAccessToken(new MemberInfo(member)); + public StompHeaders generateChairmanTokenHeader(String destination, Member member) { + String chairmanToken = jwtTokenProvider.createChairmanToken(new MemberInfo(member), 5L); StompHeaders stompHeaders = new StompHeaders(); stompHeaders.setDestination(destination); - stompHeaders.add(HttpHeaders.AUTHORIZATION, accessToken); + stompHeaders.add(HttpHeaders.AUTHORIZATION, chairmanToken); return stompHeaders; } } From 08216550802b454307e15c5ba04b6c3294eed90c Mon Sep 17 00:00:00 2001 From: coli Date: Tue, 14 Apr 2026 04:48:28 +0900 Subject: [PATCH 08/14] =?UTF-8?q?fix:=20=ED=86=A0=ED=81=B0=20resolve=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/debatetimer/controller/tool/jwt/AuthManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/debatetimer/controller/tool/jwt/AuthManager.java b/src/main/java/com/debatetimer/controller/tool/jwt/AuthManager.java index 2a6e2a51..989bf178 100644 --- a/src/main/java/com/debatetimer/controller/tool/jwt/AuthManager.java +++ b/src/main/java/com/debatetimer/controller/tool/jwt/AuthManager.java @@ -39,6 +39,6 @@ public String resolveRefreshToken(String refreshToken) { } public String resolveChairmanToken(String chairmanToken) { - return jwtTokenResolver.resolveAccessToken(chairmanToken); + return jwtTokenResolver.resolveChairmanToken(chairmanToken); } } From 2fee23e802f6f6dad5e1175a75560f676e4b26cb Mon Sep 17 00:00:00 2001 From: coli Date: Tue, 28 Apr 2026 12:17:34 +0900 Subject: [PATCH 09/14] =?UTF-8?q?feat:=20coalesce=EB=A5=BC=20=ED=86=B5?= =?UTF-8?q?=ED=95=9C=20null=20=EB=B0=A9=EC=96=B4=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repository/customize/CustomizeTimeBoxRepository.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/debatetimer/repository/customize/CustomizeTimeBoxRepository.java b/src/main/java/com/debatetimer/repository/customize/CustomizeTimeBoxRepository.java index 89d32ade..f7059b1b 100644 --- a/src/main/java/com/debatetimer/repository/customize/CustomizeTimeBoxRepository.java +++ b/src/main/java/com/debatetimer/repository/customize/CustomizeTimeBoxRepository.java @@ -13,7 +13,7 @@ public interface CustomizeTimeBoxRepository extends Repository findAllByCustomizeTable(CustomizeTableEntity table); - @Query("SELECT SUM(ctb.time) FROM CustomizeTimeBoxEntity ctb WHERE ctb.customizeTable.id = :tableId") + @Query("SELECT COALESCE(SUM(ctb.time), 0) FROM CustomizeTimeBoxEntity ctb WHERE ctb.customizeTable.id = :tableId") long sumTimeByTableId(long tableId); @Query("DELETE FROM CustomizeTimeBoxEntity ctb WHERE ctb.customizeTable.id = :tableId") From a93ab77ebd780d29044290f4eeef6031e5d2e914 Mon Sep 17 00:00:00 2001 From: coli Date: Tue, 28 Apr 2026 12:22:39 +0900 Subject: [PATCH 10/14] =?UTF-8?q?style:=20=EA=B3=B5=EB=B0=B1=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/debatetimer/controller/sharing/SharingDocumentTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/java/com/debatetimer/controller/sharing/SharingDocumentTest.java b/src/test/java/com/debatetimer/controller/sharing/SharingDocumentTest.java index ef87c825..08ec38bc 100644 --- a/src/test/java/com/debatetimer/controller/sharing/SharingDocumentTest.java +++ b/src/test/java/com/debatetimer/controller/sharing/SharingDocumentTest.java @@ -21,7 +21,6 @@ public class SharingDocumentTest extends BaseDocumentTest { - @Nested class IssueChairmanToken { From b32d635d458097fcf26bee552c1a5421839d5258 Mon Sep 17 00:00:00 2001 From: coli Date: Thu, 7 May 2026 18:06:33 +0900 Subject: [PATCH 11/14] =?UTF-8?q?refactor:=20=ED=86=A0=ED=81=B0=EB=B0=9C?= =?UTF-8?q?=EA=B8=89=20=EB=A1=9C=EC=A7=81=EC=9D=84=20=EC=BB=A8=ED=8A=B8?= =?UTF-8?q?=EB=A1=A4=EB=9F=AC=20=EA=B3=84=EC=B8=B5=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EC=9D=B4=EC=A0=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sharing/SharingRestController.java | 10 +++-- .../controller/tool/jwt/AuthManager.java | 6 +++ .../service/customize/CustomizeService.java | 5 +++ .../service/sharing/SharingService.java | 16 ------- .../sharing/SharingDocumentTest.java | 10 +++-- .../service/sharing/SharingServiceTest.java | 44 ------------------- 6 files changed, 24 insertions(+), 67 deletions(-) delete mode 100644 src/test/java/com/debatetimer/service/sharing/SharingServiceTest.java diff --git a/src/main/java/com/debatetimer/controller/sharing/SharingRestController.java b/src/main/java/com/debatetimer/controller/sharing/SharingRestController.java index 3231df17..6c99c3ba 100644 --- a/src/main/java/com/debatetimer/controller/sharing/SharingRestController.java +++ b/src/main/java/com/debatetimer/controller/sharing/SharingRestController.java @@ -1,9 +1,10 @@ package com.debatetimer.controller.sharing; import com.debatetimer.controller.auth.AuthMember; +import com.debatetimer.controller.tool.jwt.AuthManager; import com.debatetimer.domain.member.Member; import com.debatetimer.dto.sharing.response.ChairmanTokenResponse; -import com.debatetimer.service.sharing.SharingService; +import com.debatetimer.service.customize.CustomizeService; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -13,13 +14,16 @@ @RequiredArgsConstructor public class SharingRestController { - private final SharingService sharingService; + private final CustomizeService customizeService; + private final AuthManager authManager; @GetMapping("/api/share/{tableId}/chairman-token") public ChairmanTokenResponse issueChairmanToken( @AuthMember Member member, @PathVariable("tableId") long tableId ) { - return sharingService.issueChairmanToken(tableId, member); + long debateTime = customizeService.findDebateTime(tableId, member); + String chairmanToken = authManager.issueChairmanToken(member, debateTime * 2); + return new ChairmanTokenResponse(chairmanToken); } } diff --git a/src/main/java/com/debatetimer/controller/tool/jwt/AuthManager.java b/src/main/java/com/debatetimer/controller/tool/jwt/AuthManager.java index 989bf178..13ae9c42 100644 --- a/src/main/java/com/debatetimer/controller/tool/jwt/AuthManager.java +++ b/src/main/java/com/debatetimer/controller/tool/jwt/AuthManager.java @@ -1,5 +1,6 @@ package com.debatetimer.controller.tool.jwt; +import com.debatetimer.domain.member.Member; import com.debatetimer.dto.member.JwtTokenResponse; import com.debatetimer.dto.member.MemberInfo; import java.time.Duration; @@ -20,6 +21,11 @@ public JwtTokenResponse issueToken(MemberInfo memberInfo) { return new JwtTokenResponse(accessToken, refreshToken, refreshTokenExpiration); } + public String issueChairmanToken(Member member, long expiration) { + MemberInfo memberInfo = new MemberInfo(member.getEmail()); + return jwtTokenProvider.createChairmanToken(memberInfo, expiration); + } + public JwtTokenResponse reissueToken(String refreshToken) { String email = jwtTokenResolver.resolveRefreshToken(refreshToken); MemberInfo memberInfo = new MemberInfo(email); diff --git a/src/main/java/com/debatetimer/service/customize/CustomizeService.java b/src/main/java/com/debatetimer/service/customize/CustomizeService.java index 1670036f..c271f733 100644 --- a/src/main/java/com/debatetimer/service/customize/CustomizeService.java +++ b/src/main/java/com/debatetimer/service/customize/CustomizeService.java @@ -32,6 +32,11 @@ public CustomizeTableResponse findTable(long tableId, Member member) { return new CustomizeTableResponse(table, timeBoxes); } + public long findDebateTime(long tableId, Member member) { + CustomizeTable customizeTable = customizeTableDomainRepository.getByIdAndMember(tableId, member); + return customizeTableDomainRepository.getTotalTimeBoxTimes(customizeTable.getId()); + } + @Transactional public CustomizeTableResponse updateTable( CustomizeTableCreateRequest tableCreateRequest, diff --git a/src/main/java/com/debatetimer/service/sharing/SharingService.java b/src/main/java/com/debatetimer/service/sharing/SharingService.java index 11490a26..863981af 100644 --- a/src/main/java/com/debatetimer/service/sharing/SharingService.java +++ b/src/main/java/com/debatetimer/service/sharing/SharingService.java @@ -1,13 +1,7 @@ package com.debatetimer.service.sharing; -import com.debatetimer.controller.tool.jwt.JwtTokenProvider; -import com.debatetimer.domain.customize.CustomizeTable; -import com.debatetimer.domain.member.Member; import com.debatetimer.domain.sharing.TimerEvent; -import com.debatetimer.domainrepository.customize.CustomizeTableDomainRepository; -import com.debatetimer.dto.member.MemberInfo; import com.debatetimer.dto.sharing.request.SharingRequest; -import com.debatetimer.dto.sharing.response.ChairmanTokenResponse; import com.debatetimer.dto.sharing.response.SharingResponse; import com.debatetimer.dto.sharing.response.TimerEventDataResponse; import java.util.Optional; @@ -18,9 +12,6 @@ @RequiredArgsConstructor public class SharingService { - private final JwtTokenProvider jwtTokenProvider; - private final CustomizeTableDomainRepository customizeTableDomainRepository; - public SharingResponse share(SharingRequest request) { TimerEvent timerEvent = request.toTimerEvent(); return Optional.ofNullable(timerEvent.getTimerEventData()) @@ -30,11 +21,4 @@ public SharingResponse share(SharingRequest request) { )) .orElse(new SharingResponse(request.eventType(), null)); } - - public ChairmanTokenResponse issueChairmanToken(long tableId, Member member) { - CustomizeTable customizeTable = customizeTableDomainRepository.getByIdAndMember(tableId, member); - long debateTime = customizeTableDomainRepository.getTotalTimeBoxTimes(customizeTable.getId()); - String chairmanToken = jwtTokenProvider.createChairmanToken(new MemberInfo(member), debateTime * 2); - return new ChairmanTokenResponse(chairmanToken); - } } diff --git a/src/test/java/com/debatetimer/controller/sharing/SharingDocumentTest.java b/src/test/java/com/debatetimer/controller/sharing/SharingDocumentTest.java index 08ec38bc..ce082595 100644 --- a/src/test/java/com/debatetimer/controller/sharing/SharingDocumentTest.java +++ b/src/test/java/com/debatetimer/controller/sharing/SharingDocumentTest.java @@ -13,7 +13,6 @@ import com.debatetimer.controller.RestDocumentationResponse; import com.debatetimer.controller.Tag; import com.debatetimer.domain.member.Member; -import com.debatetimer.dto.sharing.response.ChairmanTokenResponse; import io.restassured.http.ContentType; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; @@ -21,6 +20,7 @@ public class SharingDocumentTest extends BaseDocumentTest { + @Nested class IssueChairmanToken { @@ -38,9 +38,11 @@ class IssueChairmanToken { @Test void 사회자_용_토큰_생성_성공() { long requestTableId = 1L; - ChairmanTokenResponse chairmanTokenResponse = new ChairmanTokenResponse("testToken"); - doReturn(chairmanTokenResponse).when(sharingService) - .issueChairmanToken(eq(requestTableId), any(Member.class)); + long debateTime = 500L; + doReturn(debateTime).when(customizeService) + .findDebateTime(eq(requestTableId), any(Member.class)); + doReturn("testToken").when(authManager) + .issueChairmanToken(any(Member.class), eq(debateTime * 2)); var document = document("sharing/get", 200) .request(requestDocument) diff --git a/src/test/java/com/debatetimer/service/sharing/SharingServiceTest.java b/src/test/java/com/debatetimer/service/sharing/SharingServiceTest.java deleted file mode 100644 index 56a1a54a..00000000 --- a/src/test/java/com/debatetimer/service/sharing/SharingServiceTest.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.debatetimer.service.sharing; - -import static org.assertj.core.api.Assertions.assertThatCode; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -import com.debatetimer.domain.customize.CustomizeBoxType; -import com.debatetimer.domain.member.Member; -import com.debatetimer.entity.customize.CustomizeTableEntity; -import com.debatetimer.exception.custom.DTClientErrorException; -import com.debatetimer.exception.errorcode.ClientErrorCode; -import com.debatetimer.service.BaseServiceTest; -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; - -class SharingServiceTest extends BaseServiceTest { - - @Autowired - private SharingService sharingService; - - @Nested - class IssueChairmanToken { - - @Test - void 사회자_토큰을_할당한다() { - Member member = memberGenerator.generate("email@email.com"); - CustomizeTableEntity tableEntity = customizeTableEntityGenerator.generate(member); - customizeTimeBoxEntityGenerator.generate(tableEntity, CustomizeBoxType.NORMAL, 1); - customizeTimeBoxEntityGenerator.generate(tableEntity, CustomizeBoxType.NORMAL, 2); - - assertThatCode(() -> sharingService.issueChairmanToken(tableEntity.getId(), member)) - .doesNotThrowAnyException(); - } - - @Test - void 회원_소유의_테이블이_아니면_에러가_발생한다() { - Member member = memberGenerator.generate("email@email.com"); - - assertThatThrownBy(() -> sharingService.issueChairmanToken(1L, member)) - .isInstanceOf(DTClientErrorException.class) - .hasMessage(ClientErrorCode.TABLE_NOT_FOUND.getMessage()); - } - } -} From d6cfeef6252d52cd9ae2662e7dcf8607857dda1c Mon Sep 17 00:00:00 2001 From: coli Date: Thu, 7 May 2026 18:14:07 +0900 Subject: [PATCH 12/14] =?UTF-8?q?test:=20=EC=84=9C=EB=B9=84=EC=8A=A4=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/customize/CustomizeService.java | 1 + .../customize/CustomizeServiceTest.java | 28 +++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/src/main/java/com/debatetimer/service/customize/CustomizeService.java b/src/main/java/com/debatetimer/service/customize/CustomizeService.java index c271f733..d143b908 100644 --- a/src/main/java/com/debatetimer/service/customize/CustomizeService.java +++ b/src/main/java/com/debatetimer/service/customize/CustomizeService.java @@ -32,6 +32,7 @@ public CustomizeTableResponse findTable(long tableId, Member member) { return new CustomizeTableResponse(table, timeBoxes); } + @Transactional(readOnly = true) public long findDebateTime(long tableId, Member member) { CustomizeTable customizeTable = customizeTableDomainRepository.getByIdAndMember(tableId, member); return customizeTableDomainRepository.getTotalTimeBoxTimes(customizeTable.getId()); diff --git a/src/test/java/com/debatetimer/service/customize/CustomizeServiceTest.java b/src/test/java/com/debatetimer/service/customize/CustomizeServiceTest.java index 664a50c5..3013abeb 100644 --- a/src/test/java/com/debatetimer/service/customize/CustomizeServiceTest.java +++ b/src/test/java/com/debatetimer/service/customize/CustomizeServiceTest.java @@ -99,6 +99,34 @@ class FindTable { } } + @Nested + class FindDebateTime { + + @Test + void 사용자_지정_토론_테이블의_총_토론_시간을_조회한다() { + Member chan = memberGenerator.generate("default@gmail.com"); + CustomizeTableEntity chanTable = customizeTableEntityGenerator.generate(chan); + customizeTimeBoxEntityGenerator.generate(chanTable, CustomizeBoxType.NORMAL, 1, 120); + customizeTimeBoxEntityGenerator.generate(chanTable, CustomizeBoxType.NORMAL, 2, 180); + + long debateTime = customizeService.findDebateTime(chanTable.getId(), chan); + + assertThat(debateTime).isEqualTo(300); + } + + @Test + void 회원_소유가_아닌_테이블_조회_시_예외를_발생시킨다() { + Member chan = memberGenerator.generate("default@gmail.com"); + Member coli = memberGenerator.generate("default2@gmail.com"); + CustomizeTableEntity chanTable = customizeTableEntityGenerator.generate(chan); + long chanTableId = chanTable.getId(); + + assertThatThrownBy(() -> customizeService.findDebateTime(chanTableId, coli)) + .isInstanceOf(DTClientErrorException.class) + .hasMessage(ClientErrorCode.TABLE_NOT_FOUND.getMessage()); + } + } + @Nested class UpdateTable { From 76b54b329c59da14137419d1d33dc268f004731c Mon Sep 17 00:00:00 2001 From: coli Date: Mon, 11 May 2026 20:23:58 +0900 Subject: [PATCH 13/14] =?UTF-8?q?style:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=EA=B3=B5=EB=B0=B1=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/debatetimer/controller/sharing/SharingDocumentTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/java/com/debatetimer/controller/sharing/SharingDocumentTest.java b/src/test/java/com/debatetimer/controller/sharing/SharingDocumentTest.java index ce082595..5c75e706 100644 --- a/src/test/java/com/debatetimer/controller/sharing/SharingDocumentTest.java +++ b/src/test/java/com/debatetimer/controller/sharing/SharingDocumentTest.java @@ -20,7 +20,6 @@ public class SharingDocumentTest extends BaseDocumentTest { - @Nested class IssueChairmanToken { From 5232baf7a24fba664612209465ff976275dedd08 Mon Sep 17 00:00:00 2001 From: coli Date: Mon, 11 May 2026 20:24:46 +0900 Subject: [PATCH 14/14] =?UTF-8?q?style:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=EA=B3=B5=EB=B0=B1=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/sharing/SharingWebSocketController.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/debatetimer/controller/sharing/SharingWebSocketController.java b/src/main/java/com/debatetimer/controller/sharing/SharingWebSocketController.java index c2ba0479..92ca689d 100644 --- a/src/main/java/com/debatetimer/controller/sharing/SharingWebSocketController.java +++ b/src/main/java/com/debatetimer/controller/sharing/SharingWebSocketController.java @@ -26,7 +26,6 @@ public SharingResponse share( @DestinationVariable(value = "roomId") long roomId, @Valid @Payload SharingRequest request ) { - return sharingService.share(request); } }