Skip to content

Commit

Permalink
feat: ✨ Turn On/Off Chat Room's Notification Setting API (#226)
Browse files Browse the repository at this point in the history
* feat: add chat-room-toggle-command

* feat: impl chat-room-notification-toggle-service

* feat: add static factory method $ validator in command

* test: service layer slice test for transation verifying

* feat: add notification turn on/off usecase

* style: move toggle service from chat-member-usecase to chat-room-usecase

* feat: open notification turn on/off api

* docs: write notification turn on/off api swagger
  • Loading branch information
psychology50 authored Jan 22, 2025
1 parent 9598bd9 commit 2a12a8f
Show file tree
Hide file tree
Showing 6 changed files with 186 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,16 @@ public interface ChatRoomApi {
@ApiResponse(responseCode = "200", description = "채팅방 관리자 모드 조회 성공", content = @Content(schemaProperties = @SchemaProperty(name = "chatRoom", schema = @Schema(implementation = ChatRoomRes.AdminView.class))))
ResponseEntity<?> getChatRoomAdmin(@PathVariable("chatRoomId") Long chatRoomId);

@Operation(summary = "채팅방 알림 켜기", method = "PATCH", description = "해당 채팅방의 요청자에 한해 알림을 켠다.")
@Parameter(name = "chatRoomId", description = "알림 설정을 변경할 채팅방의 식별자", example = "1", required = true)
@ApiResponse(responseCode = "200", description = "채팅방 알림 설정 변경 성공")
ResponseEntity<?> turnOnNotification(@PathVariable("chatRoomId") Long chatRoomId, @AuthenticationPrincipal SecurityUserDetails user);

@Operation(summary = "채팅방 알림 크기", method = "DELETE", description = "해당 채팅방의 요청자에 한해 알림을 끈다.")
@Parameter(name = "chatRoomId", description = "알림 설정을 해제할 채팅방의 식별자", example = "1", required = true)
@ApiResponse(responseCode = "200", description = "채팅방 알림 해제 성공")
ResponseEntity<?> turnOffNotification(@PathVariable("chatRoomId") Long chatRoomId, @AuthenticationPrincipal SecurityUserDetails user);

@Operation(summary = "채팅방 수정", method = "PUT", description = "채팅방의 정보를 수정한다. 채팅방의 정보 수정에 성공하면 수정된 채팅방의 상세 정보를 반환한다.")
@Parameter(name = "chatRoomId", description = "수정할 채팅방의 식별자", example = "1", required = true)
@ApiResponse(responseCode = "200", description = "채팅방 수정 성공", content = @Content(schemaProperties = @SchemaProperty(name = "chatRoom", schema = @Schema(implementation = ChatRoomRes.Detail.class))))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,24 @@ public ResponseEntity<?> getChatRoomAdmin(@PathVariable("chatRoomId") Long chatR
return ResponseEntity.ok(SuccessResponse.from(CHAT_ROOM, chatRoomUseCase.getChatRoom(chatRoomId)));
}

@Override
@PatchMapping("/{chatRoomId}")
@PreAuthorize("isAuthenticated()")
public ResponseEntity<?> turnOnNotification(@PathVariable("chatRoomId") Long chatRoomId, @AuthenticationPrincipal SecurityUserDetails user) {
chatRoomUseCase.turnOnNotification(user.getUserId(), chatRoomId);

return ResponseEntity.ok(SuccessResponse.noContent());
}

@Override
@DeleteMapping("/{chatRoomId}/notification")
@PreAuthorize("isAuthenticated()")
public ResponseEntity<?> turnOffNotification(@PathVariable("chatRoomId") Long chatRoomId, @AuthenticationPrincipal SecurityUserDetails user) {
chatRoomUseCase.turnOffNotification(user.getUserId(), chatRoomId);

return ResponseEntity.ok(SuccessResponse.noContent());
}

@Override
@PutMapping("/{chatRoomId}")
@PreAuthorize("isAuthenticated() and @chatRoomManager.hasAdminPermission(principal.userId, #chatRoomId)")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
import kr.co.pennyway.api.common.response.SliceResponseTemplate;
import kr.co.pennyway.common.annotation.UseCase;
import kr.co.pennyway.domain.context.chat.dto.ChatRoomDeleteCommand;
import kr.co.pennyway.domain.context.chat.dto.ChatRoomToggleCommand;
import kr.co.pennyway.domain.context.chat.service.ChatRoomDeleteService;
import kr.co.pennyway.domain.context.chat.service.ChatRoomNotificationToggleService;
import kr.co.pennyway.domain.domains.chatroom.domain.ChatRoom;
import kr.co.pennyway.domain.domains.chatroom.dto.ChatRoomDetail;
import lombok.RequiredArgsConstructor;
Expand All @@ -25,6 +27,7 @@ public class ChatRoomUseCase {
private final ChatRoomWithParticipantsSearchService chatRoomWithParticipantsSearchService;
private final ChatRoomPatchHelper chatRoomPatchHelper;
private final ChatRoomDeleteService chatRoomDeleteService;
private final ChatRoomNotificationToggleService chatRoomNotificationToggleService;

private final ChatMemberSearchService chatMemberSearchService;

Expand Down Expand Up @@ -76,6 +79,14 @@ public ChatRoomRes.Detail updateChatRoom(Long chatRoomId, ChatRoomReq.Update req
return ChatRoomMapper.toChatRoomResDetail(chatRoom, null, true, 1, 0);
}

public void turnOnNotification(Long userId, Long chatRoomId) {
chatRoomNotificationToggleService.turnOn(ChatRoomToggleCommand.of(userId, chatRoomId));
}

public void turnOffNotification(Long userId, Long chatRoomId) {
chatRoomNotificationToggleService.turnOff(ChatRoomToggleCommand.of(userId, chatRoomId));
}

public void deleteChatRoom(Long userId, Long chatRoomId) {
chatRoomDeleteService.execute(ChatRoomDeleteCommand.of(userId, chatRoomId));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package kr.co.pennyway.domain.context.chat.dto;

public record ChatRoomToggleCommand(
Long userId,
Long chatRoomId
) {
public ChatRoomToggleCommand {
if (userId == null) {
throw new IllegalArgumentException("userId must not be null");
}
if (chatRoomId == null) {
throw new IllegalArgumentException("chatRoomId must not be null");
}
}

public static ChatRoomToggleCommand of(Long userId, Long chatRoomId) {
return new ChatRoomToggleCommand(userId, chatRoomId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package kr.co.pennyway.domain.context.chat.service;

import kr.co.pennyway.common.annotation.DomainService;
import kr.co.pennyway.domain.context.chat.dto.ChatRoomToggleCommand;
import kr.co.pennyway.domain.domains.member.exception.ChatMemberErrorCode;
import kr.co.pennyway.domain.domains.member.exception.ChatMemberErrorException;
import kr.co.pennyway.domain.domains.member.service.ChatMemberRdbService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.annotation.Transactional;

@Slf4j
@DomainService
@RequiredArgsConstructor
public class ChatRoomNotificationToggleService {
private final ChatMemberRdbService chatMemberRdbService;

@Transactional
public void turnOn(ChatRoomToggleCommand command) {
var chatMember = chatMemberRdbService.readChatMember(command.userId(), command.chatRoomId())
.orElseThrow(() -> new ChatMemberErrorException(ChatMemberErrorCode.NOT_FOUND));

chatMember.enableNotify();

log.info("{}님이 {} 채팅방의 알림을 켰습니다.", chatMember.getId(), command.chatRoomId());
}

@Transactional
public void turnOff(ChatRoomToggleCommand command) {
var chatMember = chatMemberRdbService.readChatMember(command.userId(), command.chatRoomId())
.orElseThrow(() -> new ChatMemberErrorException(ChatMemberErrorCode.NOT_FOUND));

chatMember.disableNotify();

log.info("{}님이 {} 채팅방의 알림을 껐습니다.", chatMember.getId(), command.chatRoomId());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package kr.co.pennyway.domain.context.chat.integration;

import kr.co.pennyway.domain.common.repository.ExtendedRepositoryFactory;
import kr.co.pennyway.domain.config.DomainServiceIntegrationProfileResolver;
import kr.co.pennyway.domain.config.DomainServiceTestInfraConfig;
import kr.co.pennyway.domain.config.JpaTestConfig;
import kr.co.pennyway.domain.context.chat.dto.ChatRoomToggleCommand;
import kr.co.pennyway.domain.context.chat.service.ChatRoomNotificationToggleService;
import kr.co.pennyway.domain.context.common.fixture.ChatRoomFixture;
import kr.co.pennyway.domain.context.common.fixture.UserFixture;
import kr.co.pennyway.domain.domains.chatroom.domain.ChatRoom;
import kr.co.pennyway.domain.domains.chatroom.repository.ChatRoomRepository;
import kr.co.pennyway.domain.domains.member.domain.ChatMember;
import kr.co.pennyway.domain.domains.member.repository.ChatMemberRepository;
import kr.co.pennyway.domain.domains.member.service.ChatMemberRdbService;
import kr.co.pennyway.domain.domains.member.type.ChatMemberRole;
import kr.co.pennyway.domain.domains.user.domain.User;
import kr.co.pennyway.domain.domains.user.repository.UserRepository;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Import;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.test.context.ActiveProfiles;

import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

@Slf4j
@EnableAutoConfiguration
@SpringBootTest(classes = {ChatRoomNotificationToggleService.class, ChatMemberRdbService.class})
@EntityScan(basePackageClasses = {User.class, ChatRoom.class, ChatMember.class})
@EnableJpaRepositories(
basePackageClasses = {UserRepository.class, ChatRoomRepository.class, ChatMemberRepository.class},
repositoryFactoryBeanClass = ExtendedRepositoryFactory.class
)
@ActiveProfiles(resolver = DomainServiceIntegrationProfileResolver.class)
@Import(value = {JpaTestConfig.class})
public class ChatRoomNotificationToggleServiceIntegrationTest extends DomainServiceTestInfraConfig {
@Autowired
private ChatRoomNotificationToggleService sut;

@Autowired
private UserRepository userRepository;

@Autowired
private ChatRoomRepository chatRoomRepository;

@Autowired
private ChatMemberRepository chatMemberRepository;

@Test
@DisplayName("채팅방 알림을 켜면 알림이 켜진다.")
void shouldTurnOnWhenChatMemberExists() {
// given
var user = userRepository.save(UserFixture.GENERAL_USER.toUser());
var chatRoom = chatRoomRepository.save(ChatRoomFixture.PUBLIC_CHAT_ROOM.toEntityWithId(1L));
var chatMember = ChatMember.of(user, chatRoom, ChatMemberRole.MEMBER);
chatMember.disableNotify();
chatMember = chatMemberRepository.save(chatMember);

// when
sut.turnOn(ChatRoomToggleCommand.of(user.getId(), chatRoom.getId()));

// then
var updatedChatMember = chatMemberRepository.findById(chatMember.getId()).get();
assertTrue(updatedChatMember.isNotifyEnabled());
}

@Test
@DisplayName("채팅방 알림을 끄면 알림이 꺼진다.")
void shouldTurnOffWhenChatMemberExists() {
// given
var user = userRepository.save(UserFixture.GENERAL_USER.toUser());
var chatRoom = chatRoomRepository.save(ChatRoomFixture.PUBLIC_CHAT_ROOM.toEntityWithId(2L));
var chatMember = ChatMember.of(user, chatRoom, ChatMemberRole.MEMBER);
chatMember.enableNotify();
chatMember = chatMemberRepository.save(chatMember);

// when
sut.turnOff(ChatRoomToggleCommand.of(user.getId(), chatRoom.getId()));

// then
var updatedChatMember = chatMemberRepository.findById(chatMember.getId()).get();
assertFalse(updatedChatMember.isNotifyEnabled());
}
}

0 comments on commit 2a12a8f

Please sign in to comment.