Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,25 +1,29 @@
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;
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;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.stereotype.Controller;

@Controller
@RequiredArgsConstructor
public class SharingController {

private final SharingService sharingService;

@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 sharingService.share(request);
}
}
28 changes: 28 additions & 0 deletions src/main/java/com/debatetimer/domain/sharing/TimerEvent.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
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;
}

public TimerEvent(TimerEventType eventType) {
this(eventType, null);
}
}
46 changes: 46 additions & 0 deletions src/main/java/com/debatetimer/domain/sharing/TimerEventData.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.debatetimer.domain.sharing;

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;

@Getter
public class TimerEventData {

@NotNull
private final CustomizeBoxType timerType;

private final int sequence;

@Nullable
private final Stance currentTeam;

private final long remainingTime;

public TimerEventData(
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_DATA);
}

if (!timerType.isTimeBased() && currentTeam != null) {
throw new DTClientErrorException(ClientErrorCode.INVALID_NORMAL_TIMER_EVENT_DATA);
}
}
}
Comment on lines +11 to +46
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(질문) 여기 전부 다 NotNull 맞아요? 특정 부분은 Nullable 이라면 @Nullable 표시해주는 것이 좋지 않나요?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ 반영 완료

28 changes: 28 additions & 0 deletions src/main/java/com/debatetimer/domain/sharing/TimerEventType.java
Original file line number Diff line number Diff line change
@@ -0,0 +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(Objects::nonNull),
BEFORE(Objects::nonNull),
STOP(Objects::nonNull),
PLAY(Objects::nonNull),
RESET(Objects::nonNull),
TEAM_SWITCH(Objects::nonNull),
FINISHED(Objects::isNull),
;

private final Predicate<Object> eventDataValidator;

public void validateEventData(Object eventData) {
if (!eventDataValidator.test(eventData)) {
throw new DTClientErrorException(ClientErrorCode.INVALID_TIMER_EVENT);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,25 @@
package com.debatetimer.dto.sharing.request;

import java.time.LocalDateTime;
import com.debatetimer.domain.sharing.TimerEvent;
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(
LocalDateTime time
@NotNull
TimerEventType eventType,

@Valid
@Nullable
TimerEventInfoRequest data
) {

public TimerEvent toTimerEvent() {
return Optional.ofNullable(data)
.map(TimerEventInfoRequest::toTimerEventInfo)
.map(eventData -> new TimerEvent(eventType, eventData))
.orElseGet(() -> new TimerEvent(eventType));
}
}
Comment on lines 10 to 25
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Nullable을 다룰 때는 Optional 쓰는 게 더 좋지 않을까요?
Suggested change
public record SharingRequest(
LocalDateTime time
TimerEventType eventType,
@Valid TimerEventInfoRequest data
) {
public TimerEventInfo toTimerEventInfo() {
if (data == null) {
return null;
}
return data.toTimerEventInfo();
}
}
public record SharingRequest(
TimerEventType eventType,
@Valid @Nullable TimerEventInfoRequest data
) {
public Optional<TimerEventInfo> toTimerEventInfo() {
return Optional.ofNullable(data)
.map(TimerEventInfoRequest::toTimerEventInfo);
}
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • 이 외 코드에서는 조금 불편할 것 같은데, 어디까지 Null을 쓰고 어디까지 Null을 쓰지 않을지 잘 정해야 될 듯
  • null을 쓸거면 @Nullable을 어노테이션을 붙이고, null을 허용 안할꺼면 코드를 조금 더 복잡하게 하면서 Optional을 써야할 듯

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ [반영 완료]

Optional 반환하도록 수정했습니다

Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.debatetimer.dto.sharing.request;

import com.debatetimer.domain.customize.CustomizeBoxType;
import com.debatetimer.domain.customize.Stance;
import com.debatetimer.domain.sharing.TimerEventData;
import jakarta.annotation.Nullable;
import jakarta.validation.constraints.NotNull;

public record TimerEventInfoRequest(
@NotNull
CustomizeBoxType timerType,

@Nullable
Stance currentTeam,

int sequence,
long remainingTime
) {

public TimerEventData toTimerEventInfo() {
return new TimerEventData(
timerType,
sequence,
currentTeam,
remainingTime
);
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
package com.debatetimer.dto.sharing.response;

import java.time.LocalDateTime;
import com.debatetimer.domain.sharing.TimerEventType;
import jakarta.annotation.Nullable;

public record SharingResponse(
LocalDateTime time
TimerEventType eventType,

@Nullable
TimerEventDataResponse data
) {

public SharingResponse(TimerEventType eventType) {
this(eventType, null);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.debatetimer.dto.sharing.response;


import com.debatetimer.domain.customize.CustomizeBoxType;
import com.debatetimer.domain.customize.Stance;
import com.debatetimer.domain.sharing.TimerEventData;
import jakarta.annotation.Nullable;
import jakarta.validation.constraints.NotNull;

public record TimerEventDataResponse(
@NotNull
CustomizeBoxType timerType,

@Nullable
Stance currentTeam,

int sequence,
long remainingTime
) {

public TimerEventDataResponse(TimerEventData timerEventInfo) {
this(
timerEventInfo.getTimerType(),
timerEventInfo.getCurrentTeam(),
timerEventInfo.getSequence(),
timerEventInfo.getRemainingTime()
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,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_DATA(HttpStatus.BAD_REQUEST, "잘못된 일반 타이머 이벤트 데이터입니다"),
INVALID_TIME_BASED_TIMER_EVENT_DATA(HttpStatus.BAD_REQUEST, "잘못된 자유토론 타이머 이벤트 데이터입니다"),
INVALID_TIMER_EVENT(HttpStatus.BAD_REQUEST, "잘못된 타이머 이벤트 데이터입니다"),
;

private final HttpStatus status;
Expand Down
22 changes: 22 additions & 0 deletions src/main/java/com/debatetimer/service/sharing/SharingService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
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.TimerEventDataResponse;
import java.util.Optional;
import org.springframework.stereotype.Service;

@Service
public class SharingService {

public SharingResponse share(SharingRequest request) {
TimerEvent timerEvent = request.toTimerEvent();
return Optional.ofNullable(timerEvent.getTimerEventData())
.map(eventData -> new SharingResponse(
request.eventType(),
new TimerEventDataResponse(eventData)
))
.orElse(new SharingResponse(request.eventType(), null));
}
}
2 changes: 2 additions & 0 deletions src/test/java/com/debatetimer/BaseStompTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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 {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
Loading
Loading