Skip to content
Open
Show file tree
Hide file tree
Changes from 3 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
Expand Up @@ -9,7 +9,7 @@

import com.kickzo.main.dto.request.RoomInviteRequestDto;
import com.kickzo.main.service.InvitationService;
import com.kickzo.main.service.RoomService;
import com.kickzo.main.service.RoomQueryService;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
Expand All @@ -19,7 +19,7 @@
@RequestMapping("/api/rooms/invitations")
@RequiredArgsConstructor
public class InvitationController {
private final RoomService roomService;
private final RoomQueryService roomQueryService;
private final InvitationService invitationService;

@PostMapping()
Expand All @@ -35,7 +35,7 @@ public ResponseEntity<String> acceptInvitation(
@RequestHeader(value = "x-user-id") Long receiverId,
@RequestBody RoomInviteRequestDto inviteRequestDto) {
invitationService.acceptInvitation(receiverId, inviteRequestDto);
roomService.getRoomJoinResponse(inviteRequestDto.getRoomCode(), receiverId);
roomQueryService.getRoomJoinResponse(inviteRequestDto.getRoomCode(), receiverId);
return ResponseEntity.ok("Invitation accepted");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
import java.util.List;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
Expand All @@ -20,6 +22,7 @@
import com.kickzo.main.dto.response.RoomEntryResponseDto;
import com.kickzo.main.dto.response.UserInfoDto;
import com.kickzo.main.service.PlaylistService;
import com.kickzo.main.service.RoomQueryService;
import com.kickzo.main.service.RoomService;
import com.kickzo.main.service.RoomUserService;

Expand All @@ -34,6 +37,7 @@
public class RoomController implements RoomApi {

private final RoomService roomService;
private final RoomQueryService roomQueryService;
private final PlaylistService playlistService;
private final RoomUserService roomUserService;

Expand All @@ -44,7 +48,8 @@ public ResponseEntity<RoomEntryResponseDto> joinRoom(
@RequestBody RoomJoinRequestDto roomJoinRequestDto) {
String roomCode = roomJoinRequestDto.getRoomCode();
log.info("Join Room : UserId = {}, RoomCode = {}", userId, roomCode);
RoomEntryResponseDto response = roomService.getRoomJoinResponse(roomCode, userId);
roomService.joinRoom(roomCode, userId);
RoomEntryResponseDto response = roomQueryService.getRoomJoinResponse(roomCode, userId);
return ResponseEntity.ok(response);
}

Expand Down Expand Up @@ -86,6 +91,22 @@ public ResponseEntity<String> changeUserRole(
@GetMapping("/participants")
public ResponseEntity<List<UserInfoDto>> getRoomParticipants(
@RequestParam Long roomId) {
return ResponseEntity.ok(roomService.getRoomParticipants(roomId));
return ResponseEntity.ok(roomQueryService.getRoomParticipants(roomId));
}

@DeleteMapping("/leave/{roomId}")
public ResponseEntity<String> userLeaveRoom(
@RequestHeader(value = "x-user-id") Long userId,
@PathVariable Long roomId){
roomService.leaveRoom(roomId, userId);
return ResponseEntity.ok("Leave room successfully.");
}

@DeleteMapping("/delete/{roomId}")
public ResponseEntity<String> deleteRoom(
@RequestHeader(value = "x-user-id") Long userId,
@PathVariable Long roomId){
roomService.deleteRoom(roomId, userId);
return ResponseEntity.ok("Room deleted successfully");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
Expand Down Expand Up @@ -33,4 +34,8 @@ public interface RoomUserRepository extends JpaRepository<RoomUser, RoomUserId>

@Query(value = "SELECT EXISTS (SELECT 1 FROM room_user ru WHERE ru.room_id = :roomId AND ru.user_id = :userId)", nativeQuery = true)
Integer existsByUserIdAndRoomId(@Param("roomId") Long roomId, @Param("userId") Long userId);

@Modifying
@Query(value = "DELETE FROM room_user ru WHERE ru.room_id = :roomId", nativeQuery = true)
void deleteByRoomId(@Param("roomId") Long roomId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,12 @@ public void removeUserFromRoom(Long roomId, Long userId) {
String redisKey = "room:" + roomId + ":users";
redisActiveUsersTemplate.opsForSet().remove(redisKey, String.valueOf(userId));
}

/**
* 특정 방(roomId) 전체 제거
*/
public void removeRoom(Long roomId) {
String redisKey = "room:" + roomId + ":users";
redisActiveUsersTemplate.delete(redisKey);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package com.kickzo.main.service;

import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.Optional;
import java.util.stream.Collectors;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.kickzo.main.repository.UserEnterRedisRepository;
import com.kickzo.main.dto.data.PlaylistItem;
import com.kickzo.main.dto.response.RoomDetailsDto;
import com.kickzo.main.dto.response.RoomEntryResponseDto;
import com.kickzo.main.dto.response.RoomInfoDto;
import com.kickzo.main.dto.response.UserInfoDto;
import com.kickzo.main.entity.Playlist;
import com.kickzo.main.exception.CustomErrorCode;
import com.kickzo.main.exception.CustomException;
import com.kickzo.main.repository.PlaylistRepository;
import com.kickzo.main.repository.RoomRepository;
import com.kickzo.main.repository.RoomUserRepository;
import com.kickzo.main.repository.UserRepository;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
@Transactional(readOnly = true)
@RequiredArgsConstructor
public class RoomQueryService {

private final RoomRepository roomRepository;
private final RoomUserRepository roomUserRepository;
private final PlaylistRepository playlistRepository;
private final UserRepository userRepository;
private final UserEnterRedisRepository userEnterRedisRepository;

//방에 입장했을 때 방 정보 + 방 소속 유저 정보 + playlist 정보 제공
public RoomEntryResponseDto getRoomJoinResponse(String roomCode, Long userId){
int myRole = findUserRole(getRoomId(roomCode), userId);
RoomDetailsDto roomDetails = assembleRoomDetails(roomCode);
return new RoomEntryResponseDto(myRole, roomDetails);
}

public Integer findUserRole(Long roomId, Long userId) {
return roomUserRepository.findRoleByUserIdAndRoomId(roomId, userId);
}

public List<UserInfoDto> getRoomParticipants(Long roomId) {
return fetchUserList(roomId);
}

public Long getRoomId(String roomCode) {
return Optional.ofNullable(roomRepository.findRoomIdByRoomCode(roomCode))
.orElseThrow(() -> new CustomException(CustomErrorCode.ROOM_NOT_FOUND));
}
public String getUserProfileImage(Long userId) {
return userRepository.findProfileImageUrlById(userId);
}

public String getUserNickname(Long userId) {
return userRepository.findNicknameById(userId);
}

//주어진 역할(Role)과 방 코드를 기반으로 Room의 전체 세부 정보 생성
private RoomDetailsDto assembleRoomDetails(String roomCode) {
Long roomId = getRoomId(roomCode);

List<UserInfoDto> userList = fetchUserList(roomId);
List<RoomInfoDto> roomInfo = fetchRoomInfo(roomId);
List<PlaylistItem> playlist = fetchPlaylist(roomId);

return new RoomDetailsDto(userList, roomInfo, playlist);
}

// Room ID를 기준으로 방에 참여한 유저의 ID, Role, 닉네임, 프로필 이미지 조회
private List<UserInfoDto> fetchUserList(Long roomId) {
Set<String> onlineUsers = userEnterRedisRepository.getOnlineUsers(roomId);

List<Object[]> userIdRoles = roomUserRepository.findUsersByRoomId(roomId);
return userIdRoles.stream()
.map(userRole -> {
Long userId = (Long) userRole[0];
int role = (int) userRole[1];
String nickname = getUserNickname(userId);
String profileImageUrl = getUserProfileImage(userId);
boolean isJoined = onlineUsers != null && onlineUsers.contains(String.valueOf(userId)); // 온라인 여부 체크
return new UserInfoDto(userId, role, nickname, profileImageUrl, isJoined);
})
.collect(Collectors.toList());
}

// Room ID로 방의 정보를 조회하고 RoomInfoDto 리스트로 변환
private List<RoomInfoDto> fetchRoomInfo(Long roomId) {
return roomRepository.findRoomById(roomId)
.stream()
.map(room -> RoomInfoDto.builder()
.roomId(room.getId())
.code(room.getCode())
.title(room.getTitle())
.description(room.getDescription())
.userCount(room.getUserCount())
.creator(room.getCreator())
.profileImageUrl(getCreatorProfileImage(room.getCreator()))
.build())
.collect(Collectors.toList());
}

// Room ID를 기반으로 Playlist 정보를 JSON에서 List<PlaylistItem> 형태로 변환
private List<PlaylistItem> fetchPlaylist(Long roomId) {
return playlistRepository.findByRoomId(roomId)
.map(Playlist::getOrderAsList) // JSON → List 변환
.orElse(Collections.emptyList()); // Playlist가 없으면 빈 리스트 반환
}

private String getCreatorProfileImage(String creatorNickname) {
return userRepository.findProfileImageUrlByNickname(creatorNickname);
}
}
Loading