Skip to content
This repository has been archived by the owner on Aug 13, 2022. It is now read-only.

Commit

Permalink
Merge pull request #64 from f-lab-edu/feature/28
Browse files Browse the repository at this point in the history
[#28] 사용자의 개별 알람 읽기 기능 구현
  • Loading branch information
msugo1 committed Mar 21, 2021
2 parents 32c2c2d + 954a4c7 commit a3846d3
Show file tree
Hide file tree
Showing 8 changed files with 145 additions and 8 deletions.
11 changes: 7 additions & 4 deletions src/main/java/me/soo/helloworld/controller/AlarmController.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,7 @@
import me.soo.helloworld.annotation.LoginRequired;
import me.soo.helloworld.model.alarm.Alarm;
import me.soo.helloworld.service.AlarmService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;

import java.util.List;

Expand All @@ -25,4 +22,10 @@ public List<Alarm> getAlarmList(@CurrentUser String userId,
@RequestParam(defaultValue = "1") Integer pageNumber) {
return alarmService.getAlarmList(userId, pageNumber);
}

@LoginRequired
@GetMapping("/{alarm-id}")
public Alarm getAlarm(@CurrentUser String userId, @PathVariable("alarm-id") Integer alarmId) {
return alarmService.getAlarm(alarmId, userId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package me.soo.helloworld.exception;

public class NoSuchAlarmException extends RuntimeException {

public NoSuchAlarmException(String message) {
super(message);
}

public NoSuchAlarmException(String message, Throwable cause) {
super(message, cause);
}
}
10 changes: 9 additions & 1 deletion src/main/java/me/soo/helloworld/mapper/AlarmMapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,21 @@
import me.soo.helloworld.model.alarm.AlarmData;
import me.soo.helloworld.model.alarm.AlarmListRequest;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;
import java.util.Optional;

@Mapper
public interface AlarmMapper {

public void insertAlarm(AlarmData alarm);

List<Alarm> getAlarmList(AlarmListRequest request);
public List<Alarm> getAlarmList(AlarmListRequest request);

public Alarm getAlarm(@Param("alarmId") int alarmId, @Param("userId") String userId);

public Optional<String> getHasReadStatus(@Param("alarmId") int alarmId, @Param("userId") String userId);

public void updateToRead(@Param("alarmId") int alarmId, @Param("userId") String userId);
}
16 changes: 16 additions & 0 deletions src/main/java/me/soo/helloworld/service/AlarmService.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@

import lombok.RequiredArgsConstructor;
import me.soo.helloworld.enumeration.AlarmTypes;
import me.soo.helloworld.exception.NoSuchAlarmException;
import me.soo.helloworld.mapper.AlarmMapper;
import me.soo.helloworld.model.alarm.Alarm;
import me.soo.helloworld.model.alarm.AlarmData;
import me.soo.helloworld.model.alarm.AlarmListRequest;
import me.soo.helloworld.util.Pagination;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

Expand All @@ -29,4 +31,18 @@ public List<Alarm> getAlarmList(String userId, int pageNumber) {
return alarmMapper.getAlarmList(request);
}

@Transactional
public Alarm getAlarm(int alarmId, String userId) {
markUnreadAsRead(alarmId, userId);
return alarmMapper.getAlarm(alarmId, userId);
}

private void markUnreadAsRead(int alarmId, String userId) {
String hasRead = alarmMapper.getHasReadStatus(alarmId, userId)
.orElseThrow(() -> new NoSuchAlarmException("존재하지 않는 알람에 대한 정보는 읽어올 수 없습니다."));

if ("N".equals(hasRead)) {
alarmMapper.updateToRead(alarmId, userId);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public ResponseEntity<ExceptionResponse> checkLanguageException(final RuntimeExc
}

@ExceptionHandler(InvalidRequestException.class)
public ResponseEntity<ExceptionResponse> InvalidRequestException(final InvalidRequestException ex) {
public ResponseEntity<ExceptionResponse> invalidRequestException(final InvalidRequestException ex) {
log.error(ex.getMessage(), ex);
ExceptionResponse response = new ExceptionResponse("유효하지 않는 요청입니다.", ex.getMessage());
return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST);
Expand All @@ -68,9 +68,16 @@ public ResponseEntity<ExceptionResponse> unauthorizedAccessException(final Unaut
}

@ExceptionHandler(DuplicateRequestException.class)
public ResponseEntity<ExceptionResponse> DuplicateRequestException(final DuplicateRequestException ex) {
public ResponseEntity<ExceptionResponse> duplicateRequestException(final DuplicateRequestException ex) {
log.error(ex.getMessage(), ex);
ExceptionResponse response = new ExceptionResponse("중복된 요청입니다.", ex.getMessage());
return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST);
}

@ExceptionHandler(NoSuchAlarmException.class)
public ResponseEntity<ExceptionResponse> noSuchAlarmException (final NoSuchAlarmException ex) {
log.error(ex.getMessage(), ex);
ExceptionResponse response = new ExceptionResponse("존재하지 않는 리소스입니다.", ex.getMessage());
return new ResponseEntity<>(response, HttpStatus.NOT_FOUND);
}
}
16 changes: 16 additions & 0 deletions src/main/resources/mappers/AlarmMapper.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,20 @@
ORDER BY id DESC
LIMIT #{offset}, #{limit}
</select>

<select id="getAlarm" parameterType="map" resultType="me.soo.helloworld.model.alarm.Alarm">

SELECT id, alarmTo, alarmFrom, type, hasRead, createdAt FROM alarms
WHERE id = #{alarmId} AND alarmTo = #{userId}
</select>

<update id="updateToRead">

UPDATE alarms SET hasRead = 'Y'
WHERE id = #{alarmId} AND alarmTo = #{userId}
</update>

<select id="getHasReadStatus" parameterType="map" resultType="String">
SELECT hasRead FROM alarms WHERE id = #{alarmId} AND alarmTo = #{userId}
</select>
</mapper>
73 changes: 73 additions & 0 deletions src/test/java/me/soo/helloworld/service/AlarmServiceTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package me.soo.helloworld.service;

import me.soo.helloworld.exception.NoSuchAlarmException;
import me.soo.helloworld.mapper.AlarmMapper;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import java.util.Optional;

import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.*;


@ExtendWith(MockitoExtension.class)
public class AlarmServiceTest {

private final String to = "Soo";

private final int alarmId = 1;

@InjectMocks
AlarmService alarmService;

@Mock
AlarmMapper alarmMapper;

@Test
@DisplayName("해당 알람이 존재하지 않는 경우 hasRead 상태를 읽어오는데 실패하며 예외가 발생합니다.")
public void readAlarmFailOnNotExistingAlarm() {
when(alarmMapper.getHasReadStatus(alarmId, to)).thenReturn(Optional.empty());

assertThrows(NoSuchAlarmException.class, () -> {
alarmService.getAlarm(alarmId, to);
});

verify(alarmMapper, times(1)).getHasReadStatus(alarmId, to);
verify(alarmMapper, never()).updateToRead(alarmId, to);
verify(alarmMapper, never()).getAlarm(alarmId, to);

}

@Test
@DisplayName("해당 알람이 존재하여 기존에 읽지 않은 상태인 'N'을 리턴하는 경우 읽었다는 'Y'로 업데이트하고 알람을 읽어오는데 성공합니다.")
public void readAlarmSuccessOnExistingUnreadAlarm() {
String unRead = "N";
when(alarmMapper.getHasReadStatus(alarmId, to)).thenReturn(Optional.of(unRead));
doNothing().when(alarmMapper).updateToRead(alarmId, to);

alarmService.getAlarm(alarmId, to);

verify(alarmMapper, times(1)).getHasReadStatus(alarmId, to);
verify(alarmMapper, times(1)).updateToRead(alarmId, to);
verify(alarmMapper, times(1)).getAlarm(alarmId, to);
}

@Test
@DisplayName("해당 알람이 존재하여 기존에 읽은 상태인 'Y'를 리턴하는 경우 읽은 상태로 업데이트 하는 과정 없이 바로 알람을 읽어오는데 성공합니다.")
public void readAlarmSuccessOnExistingReadAlarm() {
String read = "Y";
when(alarmMapper.getHasReadStatus(alarmId, to)).thenReturn(Optional.of(read));

alarmService.getAlarm(alarmId, to);

verify(alarmMapper, times(1)).getHasReadStatus(alarmId, to);
verify(alarmMapper, never()).updateToRead(alarmId, to);
verify(alarmMapper, times(1)).getAlarm(alarmId, to);
}

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package me.soo.helloworld.service;

import me.soo.helloworld.enumeration.FriendStatus;
import me.soo.helloworld.exception.DuplicateRequestException;
import me.soo.helloworld.exception.InvalidRequestException;
import me.soo.helloworld.mapper.FriendMapper;
Expand Down Expand Up @@ -34,6 +33,9 @@ public class FriendServiceTest {
@Mock
UserService userService;

@Mock
AlarmService alarmService;

/*
친구 요청을 보낼 때 발생할 수 있는 예외들
Expand Down

0 comments on commit a3846d3

Please sign in to comment.