Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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 @@ -56,7 +56,7 @@ public void removeChatRoom(ChatRoomDeleteRequest request, String email) {

ChatRoom removedRoom = chattingDomainService.getChatRoom(request.roomId());

chattingDomainService.isChatRoomOwner(removedRoom, user.getId());
chattingDomainService.checkChatRoomOwnerOrAdmin(removedRoom, user);

chattingDomainService.removeChatRoom(removedRoom);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,15 @@
import org.ezcode.codetest.domain.game.model.item.Item;
import org.ezcode.codetest.domain.game.model.skill.Skill;
import org.ezcode.codetest.domain.game.service.GameManagementDomainService;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import lombok.RequiredArgsConstructor;

@Service
@RequiredArgsConstructor
@PreAuthorize("hasRole('ADMIN')")
public class GameAdminUseCase {

private final GameManagementDomainService managementService;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ public interface ChatRepository {

Chat save(Chat chat);

List<Chat> findAll();

List<Chat> findChatsFromLastHour(Long roomId);

}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
import org.ezcode.codetest.domain.chat.model.ChatRoom;
import org.ezcode.codetest.domain.chat.repository.ChatRepository;
import org.ezcode.codetest.domain.chat.repository.ChatRoomRepository;
import org.ezcode.codetest.domain.user.model.entity.User;
import org.ezcode.codetest.domain.user.model.enums.UserRole;
import org.springframework.stereotype.Component;

import lombok.RequiredArgsConstructor;
Expand All @@ -29,9 +31,9 @@ public void removeChatRoom(ChatRoom room) {
chatRoomRepository.delete(room);
}

public void isChatRoomOwner(ChatRoom room, Long userId) {
public void checkChatRoomOwnerOrAdmin(ChatRoom room, User user) {

if(!room.isOwner(userId)) {
if (!room.isOwner(user.getId()) && user.getRole() != UserRole.ADMIN) {
throw new ChattingException(ChattingExceptionCode.CHATROOM_NOT_OWNER);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.ezcode.codetest.infrastructure.event.dto;

public record GameLevelUpEvent(

Long userId,

boolean isProblemSolved,

String problemCategory

) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import org.ezcode.codetest.infrastructure.event.dto.ChatRoomParticipantCountChangeEvent;
import org.ezcode.codetest.infrastructure.event.dto.ChatRoomEntryExitMessageEvent;
import org.ezcode.codetest.infrastructure.event.dto.ChatRoomHistoryLoadEvent;
import org.ezcode.codetest.infrastructure.event.service.StompMessageService;
import org.ezcode.codetest.infrastructure.event.publisher.StompMessageService;
import org.springframework.stereotype.Component;
import org.springframework.transaction.event.TransactionPhase;
import org.springframework.transaction.event.TransactionalEventListener;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package org.ezcode.codetest.infrastructure.event.listener;

import org.ezcode.codetest.domain.game.service.CharacterStatusDomainService;
import org.ezcode.codetest.infrastructure.event.dto.GameLevelUpEvent;
import org.springframework.stereotype.Component;
import org.springframework.transaction.event.TransactionPhase;
import org.springframework.transaction.event.TransactionalEventListener;

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

@Slf4j
@Component
@RequiredArgsConstructor
public class GameLevelUpListener {

private final CharacterStatusDomainService characterDomainService;

@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void handleGameCharacterLevelUp(GameLevelUpEvent event) {

characterDomainService.gameCharacterLevelUp(event.userId(), event.isProblemSolved(), event.problemCategory());
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

에러 처리 및 로깅 추가 필요

현재 구현에서는 도메인 서비스 호출 시 발생할 수 있는 예외에 대한 처리가 없고, 로깅 어노테이션이 있음에도 불구하고 실제 로깅이 구현되지 않았습니다.

다음과 같이 에러 처리와 로깅을 추가해주세요:

 @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
 public void handleGameCharacterLevelUp(GameLevelUpEvent event) {
+    try {
+        log.info("게임 레벨업 이벤트 처리 시작 - userId: {}, isProblemSolved: {}, category: {}", 
+                 event.userId(), event.isProblemSolved(), event.problemCategory());
+        
         characterDomainService.gameCharacterLevelUp(event.userId(), event.isProblemSolved(), event.problemCategory());
+        
+        log.info("게임 레벨업 이벤트 처리 완료 - userId: {}", event.userId());
+    } catch (Exception e) {
+        log.error("게임 레벨업 이벤트 처리 중 오류 발생 - userId: {}, error: {}", 
+                  event.userId(), e.getMessage(), e);
+        // 필요에 따라 재시도 로직이나 알림 로직 추가 고려
+    }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void handleGameCharacterLevelUp(GameLevelUpEvent event) {
characterDomainService.gameCharacterLevelUp(event.userId(), event.isProblemSolved(), event.problemCategory());
}
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void handleGameCharacterLevelUp(GameLevelUpEvent event) {
try {
log.info("게임 레벨업 이벤트 처리 시작 - userId: {}, isProblemSolved: {}, category: {}",
event.userId(), event.isProblemSolved(), event.problemCategory());
characterDomainService.gameCharacterLevelUp(event.userId(), event.isProblemSolved(), event.problemCategory());
log.info("게임 레벨업 이벤트 처리 완료 - userId: {}", event.userId());
} catch (Exception e) {
log.error("게임 레벨업 이벤트 처리 중 오류 발생 - userId: {}, error: {}",
event.userId(), e.getMessage(), e);
// 필요에 따라 재시도 로직이나 알림 로직 추가 고려
}
}
🤖 Prompt for AI Agents
In
src/main/java/org/ezcode/codetest/infrastructure/event/listener/GameLevelUpListener.java
around lines 19 to 23, the method handleGameCharacterLevelUp lacks error
handling and does not perform any logging despite having logging annotations.
Wrap the call to characterDomainService.gameCharacterLevelUp in a try-catch
block to catch potential exceptions, log the error details using the logger, and
handle the exception appropriately to prevent it from propagating uncaught.


}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import org.ezcode.codetest.application.notification.event.NotificationReadEvent;
import org.ezcode.codetest.infrastructure.event.dto.NotificationRecord;
import org.ezcode.codetest.infrastructure.event.dto.NotificationResponse;
import org.ezcode.codetest.infrastructure.event.service.StompMessageService;
import org.ezcode.codetest.infrastructure.event.publisher.StompMessageService;
import org.ezcode.codetest.infrastructure.persistence.repository.notification.NotificationRepository;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import org.ezcode.codetest.domain.chat.model.ChatRoom;
import org.ezcode.codetest.domain.chat.service.ChattingDomainService;
import org.ezcode.codetest.domain.user.service.UserDomainService;
import org.ezcode.codetest.infrastructure.event.service.StompMessageService;
import org.ezcode.codetest.infrastructure.event.publisher.StompMessageService;
import org.ezcode.codetest.infrastructure.session.service.RedisSessionCountService;
import org.springframework.context.ApplicationListener;
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.ezcode.codetest.infrastructure.event.service;
package org.ezcode.codetest.infrastructure.event.publisher;

import org.ezcode.codetest.application.chatting.port.event.ChatEventService;
import org.ezcode.codetest.infrastructure.event.dto.ChatMessageBroadcastEvent;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.ezcode.codetest.infrastructure.event.service;
package org.ezcode.codetest.infrastructure.event.publisher;

import java.time.Instant;
import java.util.List;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.ezcode.codetest.infrastructure.event.service;
package org.ezcode.codetest.infrastructure.event.publisher;

import org.ezcode.codetest.application.notification.event.NotificationCreateEvent;
import org.ezcode.codetest.application.notification.event.NotificationListRequestEvent;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package org.ezcode.codetest.infrastructure.event.publisher;

import org.ezcode.codetest.domain.submission.model.entity.UserProblemResult;
import org.ezcode.codetest.infrastructure.event.dto.GameLevelUpEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;

import lombok.RequiredArgsConstructor;

@Component
@RequiredArgsConstructor
public class ProblemEventPublisher {

private final ApplicationEventPublisher publisher;

public void publishProblemSolveEvent(UserProblemResult event) {

Long userId = event.getUser().getId();
boolean isCorrect = event.isCorrect();
String problemCategory = event.getProblem().getCategory().getDescription();

publisher.publishEvent(new GameLevelUpEvent(userId, isCorrect, problemCategory));
}
Comment on lines +16 to +23
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

널 안전성 검증 추가 필요

현재 구현에서는 event, event.getUser(), event.getProblem(), event.getProblem().getCategory() 등의 null 체크가 누락되어 있어 NullPointerException이 발생할 수 있습니다.

다음과 같이 수정하여 null 안전성을 보장해주세요:

 public void publishProblemSolveEvent(UserProblemResult event) {
+    if (event == null || event.getUser() == null || event.getProblem() == null 
+        || event.getProblem().getCategory() == null) {
+        throw new IllegalArgumentException("UserProblemResult와 관련 객체들은 null일 수 없습니다");
+    }

     Long userId = event.getUser().getId();
     boolean isCorrect = event.isCorrect();
     String problemCategory = event.getProblem().getCategory().getDescription();

     publisher.publishEvent(new GameLevelUpEvent(userId, isCorrect, problemCategory));
 }
🤖 Prompt for AI Agents
In
src/main/java/org/ezcode/codetest/infrastructure/event/publisher/ProblemEventPublisher.java
between lines 16 and 23, add null checks for event, event.getUser(),
event.getProblem(), and event.getProblem().getCategory() before accessing their
methods to prevent NullPointerException. Implement conditional checks that
return early or handle null cases safely to ensure null safety in the
publishProblemSolveEvent method.

}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.ezcode.codetest.infrastructure.event.service;
package org.ezcode.codetest.infrastructure.event.publisher;

import java.util.Map;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.ezcode.codetest.infrastructure.event.service;
package org.ezcode.codetest.infrastructure.event.publisher;

import org.springframework.messaging.simp.SimpMessageHeaderAccessor;
import org.springframework.messaging.simp.SimpMessageType;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,6 @@ public Chat save(Chat chat) {
return chatRepository.save(chat);
}

@Override
public List<Chat> findAll() {

return chatRepository.findAll();
}

@Override
public List<Chat> findChatsFromLastHour(Long roomId) {

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package org.ezcode.codetest.presentation.chattingmanagement.chatting.config;
package org.ezcode.codetest.presentation.chatting.chatting.config;

import org.ezcode.codetest.presentation.chattingmanagement.chatting.interceptor.ChatLimitInterceptor;
import org.ezcode.codetest.presentation.chatting.chatting.interceptor.ChatLimitInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
Expand All @@ -16,6 +16,6 @@ public class ChatWebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(chatSpamInterceptor)
.addPathPatterns("/api/room/*/chat");
.addPathPatterns("/api/rooms/*/chat");
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.ezcode.codetest.presentation.chattingmanagement.chatting.controller;
package org.ezcode.codetest.presentation.chatting.chatting.controller;

import org.ezcode.codetest.application.chatting.dto.request.ChatSaveRequest;
import org.ezcode.codetest.application.chatting.service.ChattingUseCase;
Expand All @@ -14,7 +14,7 @@
import lombok.RequiredArgsConstructor;

@Controller
@RequestMapping("/api/room/{roomId}/chat")
@RequestMapping("/api/rooms/{roomId}/chat")
@RequiredArgsConstructor
public class ChatController {

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.ezcode.codetest.presentation.chattingmanagement.chatting.controller;
package org.ezcode.codetest.presentation.chatting.chatting.controller;

import org.ezcode.codetest.application.chatting.dto.request.ChatRoomDeleteRequest;
import org.ezcode.codetest.application.chatting.dto.request.ChatRoomSaveRequest;
Expand All @@ -21,7 +21,7 @@

@RestController
@RequiredArgsConstructor
@RequestMapping("/api/chatrooms")
@RequestMapping("/api/rooms")
public class ChatRoomController {

private final ChattingUseCase chatUseCase;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.ezcode.codetest.presentation.chattingmanagement.chatting.interceptor;
package org.ezcode.codetest.presentation.chatting.chatting.interceptor;

import java.util.Map;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.ezcode.codetest.presentation.chattingmanagement.event;
package org.ezcode.codetest.presentation.chatting.event;

import java.security.Principal;

Expand All @@ -25,7 +25,7 @@ public void handleGetChatRoomList(
chatUseCase.getChatRoomList(principal.getName(), sessionId);
}

@MessageMapping("/room/{roomId}/enter")
@MessageMapping("/rooms/{roomId}/enter")
public void handleGetChattingHistory(
Principal principal,
@DestinationVariable Long roomId,
Expand All @@ -35,7 +35,7 @@ public void handleGetChattingHistory(
chatUseCase.getChattingHistory(sessionId, principal.getName(), principal.getName(), roomId);
}

@MessageMapping("/room/{roomId}/left")
@MessageMapping("/rooms/{roomId}/left")
public void handleChatRoomLeft(
Principal principal,
@DestinationVariable Long roomId,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.ezcode.codetest.presentation.chattingmanagement.view;
package org.ezcode.codetest.presentation.chatting.view;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
Expand Down
6 changes: 3 additions & 3 deletions src/main/resources/templates/chat-page.html
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ <h2>채팅방 목록</h2>
const nr = li.dataset.roomId;
if (!nr || currentRoomId === nr) return;
if (chatSubscription && currentRoomId) {
stompClient.send(`/chat/room/${currentRoomId}/left`, {}, currentRoomId);
stompClient.send(`/chat/rooms/${currentRoomId}/left`, {}, currentRoomId);
chatSubscription.unsubscribe();
}
currentRoomId = nr;
Expand Down Expand Up @@ -337,7 +337,7 @@ <h2>채팅방 목록</h2>
}, 100);
});
setTimeout(() => {
stompClient.send(`/chat/room/${nr}/enter`, {}, nr);
stompClient.send(`/chat/rooms/${nr}/enter`, {}, nr);
}, 100);
}, 100);
});
Expand All @@ -352,7 +352,7 @@ <h2>채팅방 목록</h2>
if (!currentRoomId) return;
const m = msgInput.value.trim();
if (!m) return;
fetch(`/api/room/${currentRoomId}/chat`, {
fetch(`/api/rooms/${currentRoomId}/chat`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import static org.mockito.Mockito.*;

import java.util.List;
import java.util.Map;
import java.util.stream.Stream;

import org.ezcode.codetest.application.chatting.dto.request.ChatRoomDeleteRequest;
Expand Down Expand Up @@ -168,7 +167,7 @@ void removeChatRoom() {
// then
verify(userDomainService).getUser(TEST_EMAIL);
verify(chattingDomainService).getChatRoom(TEST_ROOM_ID);
verify(chattingDomainService).isChatRoomOwner(chatRoom1, user.getId());
verify(chattingDomainService).checkChatRoomOwnerOrAdmin(chatRoom1, user);
verify(chattingDomainService).removeChatRoom(chatRoom1);

ArgumentCaptor<ChatRoomCache> cacheCaptor = ArgumentCaptor.forClass(ChatRoomCache.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ class ChattingDomainServiceTest {
private ChatRoom chatRoom;

private User user;
private User wrongUser;
private Chat chat;

private static final Long TEST_ROOM_ID = 1L;
Expand All @@ -61,8 +62,19 @@ void setUp() {
.age(22)
.build();

wrongUser = User.builder()
.email(TEST_EMAIL)
.username("익명2")
.password("P@ssw0rd12252")
.nickname("익명 닉네임22")
.tier(Tier.NEWBIE)
.age(22)
.build();

ReflectionTestUtils.setField(user, "id", TEST_ROOM_ID);

ReflectionTestUtils.setField(wrongUser, "id", WRONG_USER_ID);

chatRoom = ChatRoom.builder()
.title(TEMP_TITLE_1)
.user(user)
Expand Down Expand Up @@ -114,11 +126,11 @@ void isChatRoomOwner() {
doReturn(true).when(chatRoom).isOwner(user.getId());

// when
chattingDomainService.isChatRoomOwner(chatRoom, user.getId());
chattingDomainService.checkChatRoomOwnerOrAdmin(chatRoom, user);

// then
assertDoesNotThrow(() ->
chattingDomainService.isChatRoomOwner(chatRoom, user.getId())
chattingDomainService.checkChatRoomOwnerOrAdmin(chatRoom, user)
);
}

Expand Down Expand Up @@ -184,7 +196,7 @@ void isChatRoomOwner() {

// when
ChattingException exception = assertThrows(ChattingException.class,
() -> chattingDomainService.isChatRoomOwner(chatRoom, WRONG_USER_ID));
() -> chattingDomainService.checkChatRoomOwnerOrAdmin(chatRoom, wrongUser));

// then
assertAll(
Expand Down