diff --git a/src/main/java/com/back/domain/studyroom/controller/RoomController.java b/src/main/java/com/back/domain/studyroom/controller/RoomController.java index fcf58e7e..0d8c8e8c 100644 --- a/src/main/java/com/back/domain/studyroom/controller/RoomController.java +++ b/src/main/java/com/back/domain/studyroom/controller/RoomController.java @@ -43,7 +43,7 @@ public class RoomController { @PostMapping @Operation( summary = "방 생성", - description = "새로운 스터디 룸을 생성합니다. 방 생성자는 자동으로 방장(HOST)이 됩니다." + description = "새로운 스터디 룸을 생성합니다. 방 생성자는 자동으로 방장(HOST)이 됩니다. useWebRTC로 화상/음성/화면공유 기능을 한 번에 제어할 수 있습니다." ) @ApiResponses({ @ApiResponse(responseCode = "201", description = "방 생성 성공"), @@ -61,7 +61,8 @@ public ResponseEntity> createRoom( request.getIsPrivate() != null ? request.getIsPrivate() : false, request.getPassword(), request.getMaxParticipants() != null ? request.getMaxParticipants() : 10, - currentUserId + currentUserId, + request.getUseWebRTC() != null ? request.getUseWebRTC() : true // 디폴트: true ); RoomResponse response = roomService.toRoomResponse(room); diff --git a/src/main/java/com/back/domain/studyroom/dto/CreateRoomRequest.java b/src/main/java/com/back/domain/studyroom/dto/CreateRoomRequest.java index 46a4672d..0dd78295 100644 --- a/src/main/java/com/back/domain/studyroom/dto/CreateRoomRequest.java +++ b/src/main/java/com/back/domain/studyroom/dto/CreateRoomRequest.java @@ -23,4 +23,10 @@ public class CreateRoomRequest { @Min(value = 2, message = "최소 2명 이상이어야 합니다") @Max(value = 100, message = "최대 100명까지 가능합니다") private Integer maxParticipants = 10; + + // WebRTC 통합 제어 필드 (카메라, 오디오, 화면공유를 한 번에 제어) + // true: WebRTC 기능 전체 활성화 + // false: WebRTC 기능 전체 비활성화 + // null: 디폴트 true로 처리 + private Boolean useWebRTC = true; } diff --git a/src/main/java/com/back/domain/studyroom/dto/RoomResponse.java b/src/main/java/com/back/domain/studyroom/dto/RoomResponse.java index bd3960fb..1f22a5aa 100644 --- a/src/main/java/com/back/domain/studyroom/dto/RoomResponse.java +++ b/src/main/java/com/back/domain/studyroom/dto/RoomResponse.java @@ -19,6 +19,11 @@ public class RoomResponse { private String createdBy; private LocalDateTime createdAt; + // WebRTC 설정 정보 (프론트엔드에서 UI 제어용) + private Boolean allowCamera; + private Boolean allowAudio; + private Boolean allowScreenShare; + public static RoomResponse from(Room room, long currentParticipants) { return RoomResponse.builder() .roomId(room.getId()) @@ -29,6 +34,9 @@ public static RoomResponse from(Room room, long currentParticipants) { .status(room.getStatus()) .createdBy(room.getCreatedBy().getNickname()) .createdAt(room.getCreatedAt()) + .allowCamera(room.isAllowCamera()) + .allowAudio(room.isAllowAudio()) + .allowScreenShare(room.isAllowScreenShare()) .build(); } } diff --git a/src/main/java/com/back/domain/studyroom/entity/Room.java b/src/main/java/com/back/domain/studyroom/entity/Room.java index 98d681cf..dea501d0 100644 --- a/src/main/java/com/back/domain/studyroom/entity/Room.java +++ b/src/main/java/com/back/domain/studyroom/entity/Room.java @@ -168,9 +168,11 @@ public boolean isOwner(Long userId) { * 방 생성을 위한 정적 팩토리 메서드 새로운 방을 생성할 때 모든 기본값을 설정 해주는 초기 메서드 기본 상태에서 방장이 임의로 변형하고 싶은 부분만 변경해서 사용 가능 + * @param useWebRTC WebRTC 사용 여부 (true: 카메라/오디오/화면공유 전체 활성화, false: 전체 비활성화) */ public static Room create(String title, String description, boolean isPrivate, - String password, int maxParticipants, User creator, RoomTheme theme) { + String password, int maxParticipants, User creator, RoomTheme theme, + boolean useWebRTC) { Room room = new Room(); room.title = title; room.description = description; @@ -178,9 +180,9 @@ public static Room create(String title, String description, boolean isPrivate, room.password = password; room.maxParticipants = maxParticipants; room.isActive = true; // 생성 시 기본적으로 활성화 - room.allowCamera = true; // 기본적으로 카메라 허용 - room.allowAudio = true; // 기본적으로 오디오 허용 - room.allowScreenShare = true; // 기본적으로 화면 공유 허용 + room.allowCamera = useWebRTC; // WebRTC 사용 여부에 따라 설정 + room.allowAudio = useWebRTC; // WebRTC 사용 여부에 따라 설정 + room.allowScreenShare = useWebRTC; // WebRTC 사용 여부에 따라 설정 room.status = RoomStatus.WAITING; // 생성 시 대기 상태 room.currentParticipants = 0; // 생성 시 참가자 0명 room.createdBy = creator; diff --git a/src/main/java/com/back/domain/studyroom/service/RoomService.java b/src/main/java/com/back/domain/studyroom/service/RoomService.java index 21d25907..71f0f57c 100644 --- a/src/main/java/com/back/domain/studyroom/service/RoomService.java +++ b/src/main/java/com/back/domain/studyroom/service/RoomService.java @@ -52,17 +52,17 @@ public class RoomService { * 기본 설정: - 상태: WAITING (대기 중) - - 카메라/오디오/화면공유: application.yml의 설정값 사용 + - WebRTC: useWebRTC 파라미터에 따라 카메라/오디오/화면공유 통합 제어 - 참가자 수: 0명에서 시작 후 방장 추가로 1명 */ @Transactional public Room createRoom(String title, String description, boolean isPrivate, - String password, int maxParticipants, Long creatorId) { + String password, int maxParticipants, Long creatorId, boolean useWebRTC) { User creator = userRepository.findById(creatorId) .orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND)); - Room room = Room.create(title, description, isPrivate, password, maxParticipants, creator, null); + Room room = Room.create(title, description, isPrivate, password, maxParticipants, creator, null, useWebRTC); Room savedRoom = roomRepository.save(room); RoomMember hostMember = RoomMember.createHost(savedRoom, creator); @@ -70,8 +70,8 @@ public Room createRoom(String title, String description, boolean isPrivate, // savedRoom.incrementParticipant(); // Redis로 이관 - DB 업데이트 제거 - log.info("방 생성 완료 - RoomId: {}, Title: {}, CreatorId: {}", - savedRoom.getId(), title, creatorId); + log.info("방 생성 완료 - RoomId: {}, Title: {}, CreatorId: {}, WebRTC: {}", + savedRoom.getId(), title, creatorId, useWebRTC); return savedRoom; } @@ -127,7 +127,7 @@ public RoomMember joinRoom(Long roomId, String password, Long userId) { // TODO: Redis에서 온라인 여부 확인하도록 변경 // 현재는 기존 멤버 재입장 허용 // room.incrementParticipant(); // Redis로 이관 - DB 업데이트 제거 - room.incrementParticipant(); + return member; } diff --git a/src/test/java/com/back/domain/studyroom/controller/RoomControllerTest.java b/src/test/java/com/back/domain/studyroom/controller/RoomControllerTest.java index 63fc1475..ad9c2d25 100644 --- a/src/test/java/com/back/domain/studyroom/controller/RoomControllerTest.java +++ b/src/test/java/com/back/domain/studyroom/controller/RoomControllerTest.java @@ -66,7 +66,7 @@ void setUp() { userProfile.setNickname("테스트유저"); testUser.setUserProfile(userProfile); - // 테스트 방 생성 + // 테스트 방 생성 (WebRTC 사용) testRoom = Room.create( "테스트 방", "테스트 설명", @@ -74,7 +74,8 @@ void setUp() { null, 10, testUser, - null + null, + true // useWebRTC ); // 테스트 멤버 생성 @@ -94,7 +95,8 @@ void createRoom() { "테스트 설명", false, null, - 10 + 10, + true // useWebRTC ); given(roomService.createRoom( @@ -103,7 +105,8 @@ void createRoom() { anyBoolean(), any(), anyInt(), - eq(1L) + eq(1L), + anyBoolean() // useWebRTC 파라미터 추가 )).willReturn(testRoom); RoomResponse roomResponse = RoomResponse.from(testRoom, 1); @@ -125,7 +128,8 @@ void createRoom() { anyBoolean(), any(), anyInt(), - eq(1L) + eq(1L), + anyBoolean() // useWebRTC 파라미터 추가 ); verify(roomService, times(1)).toRoomResponse(any(Room.class)); } @@ -365,5 +369,126 @@ void getPopularRooms() { verify(roomService, times(1)).getPopularRooms(any()); verify(roomService, times(1)).toRoomResponseList(anyList()); + + } + + @Test + @DisplayName("방 생성 API - WebRTC 활성화 테스트") + void createRoom_WithWebRTC() { + // given + given(currentUser.getUserId()).willReturn(1L); + + CreateRoomRequest request = new CreateRoomRequest( + "WebRTC 방", + "화상 채팅 가능", + false, + null, + 10, + true // WebRTC 활성화 + ); + + Room webRTCRoom = Room.create( + "WebRTC 방", + "화상 채팅 가능", + false, + null, + 10, + testUser, + null, + true + ); + + given(roomService.createRoom( + anyString(), + anyString(), + anyBoolean(), + any(), + anyInt(), + eq(1L), + eq(true) // WebRTC true 검증 + )).willReturn(webRTCRoom); + + RoomResponse roomResponse = RoomResponse.from(webRTCRoom, 1); + given(roomService.toRoomResponse(any(Room.class))).willReturn(roomResponse); + + // when + ResponseEntity> response = roomController.createRoom(request); + + // then + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.CREATED); + assertThat(response.getBody()).isNotNull(); + assertThat(response.getBody().getData().getAllowCamera()).isTrue(); + assertThat(response.getBody().getData().getAllowAudio()).isTrue(); + assertThat(response.getBody().getData().getAllowScreenShare()).isTrue(); + + verify(roomService, times(1)).createRoom( + anyString(), + anyString(), + anyBoolean(), + any(), + anyInt(), + eq(1L), + eq(true) + ); + } + + @Test + @DisplayName("방 생성 API - WebRTC 비활성화 테스트") + void createRoom_WithoutWebRTC() { + // given + given(currentUser.getUserId()).willReturn(1L); + + CreateRoomRequest request = new CreateRoomRequest( + "채팅 전용 방", + "텍스트만 가능", + false, + null, + 50, + false // WebRTC 비활성화 + ); + + Room chatOnlyRoom = Room.create( + "채팅 전용 방", + "텍스트만 가능", + false, + null, + 50, + testUser, + null, + false + ); + + given(roomService.createRoom( + anyString(), + anyString(), + anyBoolean(), + any(), + anyInt(), + eq(1L), + eq(false) // WebRTC false 검증 + )).willReturn(chatOnlyRoom); + + RoomResponse roomResponse = RoomResponse.from(chatOnlyRoom, 1); + given(roomService.toRoomResponse(any(Room.class))).willReturn(roomResponse); + + // when + ResponseEntity> response = roomController.createRoom(request); + + // then + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.CREATED); + assertThat(response.getBody()).isNotNull(); + assertThat(response.getBody().getData().getAllowCamera()).isFalse(); + assertThat(response.getBody().getData().getAllowAudio()).isFalse(); + assertThat(response.getBody().getData().getAllowScreenShare()).isFalse(); + + verify(roomService, times(1)).createRoom( + anyString(), + anyString(), + anyBoolean(), + any(), + anyInt(), + eq(1L), + eq(false) + ); } } diff --git a/src/test/java/com/back/domain/studyroom/service/RoomServiceTest.java b/src/test/java/com/back/domain/studyroom/service/RoomServiceTest.java index d7262668..d9f1c7a7 100644 --- a/src/test/java/com/back/domain/studyroom/service/RoomServiceTest.java +++ b/src/test/java/com/back/domain/studyroom/service/RoomServiceTest.java @@ -71,7 +71,7 @@ void setUp() { userProfile.setNickname("테스트유저"); testUser.setUserProfile(userProfile); - // 테스트 방 생성 + // 테스트 방 생성 (WebRTC 사용) testRoom = Room.create( "테스트 방", "테스트 설명", @@ -79,7 +79,8 @@ void setUp() { null, 10, testUser, - null + null, + true // useWebRTC ); // 테스트 멤버 생성 @@ -101,7 +102,8 @@ void createRoom_Success() { false, null, 10, - 1L + 1L, + true // useWebRTC ); // then @@ -125,7 +127,8 @@ void createRoom_UserNotFound() { false, null, 10, - 999L + 999L, + true // useWebRTC )) .isInstanceOf(CustomException.class) .hasFieldOrPropertyWithValue("errorCode", ErrorCode.USER_NOT_FOUND); @@ -171,7 +174,8 @@ void joinRoom_WrongPassword() { "1234", 10, testUser, - null + null, + true // useWebRTC ); given(roomRepository.findByIdWithLock(1L)).willReturn(Optional.of(privateRoom)); @@ -242,7 +246,8 @@ void getRoomDetail_PrivateRoomForbidden() { "1234", 10, testUser, - null + null, + true // useWebRTC ); given(roomRepository.findById(1L)).willReturn(Optional.of(privateRoom)); given(roomMemberRepository.existsByRoomIdAndUserId(1L, 2L)).willReturn(false); @@ -387,4 +392,56 @@ void kickMember_NoPermission() { .isInstanceOf(CustomException.class) .hasFieldOrPropertyWithValue("errorCode", ErrorCode.NOT_ROOM_MANAGER); } + + @Test + @DisplayName("방 생성 - WebRTC 활성화") + void createRoom_WithWebRTC() { + // given + given(userRepository.findById(1L)).willReturn(Optional.of(testUser)); + given(roomRepository.save(any(Room.class))).willAnswer(invocation -> invocation.getArgument(0)); + given(roomMemberRepository.save(any(RoomMember.class))).willReturn(testMember); + + // when + Room createdRoom = roomService.createRoom( + "WebRTC 방", + "화상 채팅 가능", + false, + null, + 10, + 1L, + true // WebRTC 사용 + ); + + // then + assertThat(createdRoom).isNotNull(); + assertThat(createdRoom.isAllowCamera()).isTrue(); + assertThat(createdRoom.isAllowAudio()).isTrue(); + assertThat(createdRoom.isAllowScreenShare()).isTrue(); + } + + @Test + @DisplayName("방 생성 - WebRTC 비활성화") + void createRoom_WithoutWebRTC() { + // given + given(userRepository.findById(1L)).willReturn(Optional.of(testUser)); + given(roomRepository.save(any(Room.class))).willAnswer(invocation -> invocation.getArgument(0)); + given(roomMemberRepository.save(any(RoomMember.class))).willReturn(testMember); + + // when + Room createdRoom = roomService.createRoom( + "채팅 전용 방", + "텍스트만 가능", + false, + null, + 50, // WebRTC 없으면 더 많은 인원 가능 + 1L, + false // WebRTC 미사용 + ); + + // then + assertThat(createdRoom).isNotNull(); + assertThat(createdRoom.isAllowCamera()).isFalse(); + assertThat(createdRoom.isAllowAudio()).isFalse(); + assertThat(createdRoom.isAllowScreenShare()).isFalse(); + } }