diff --git a/backend/src/main/java/com/votogether/domain/alarm/controller/AlarmCommandController.java b/backend/src/main/java/com/votogether/domain/alarm/controller/AlarmCommandController.java new file mode 100644 index 000000000..9df9e9cf6 --- /dev/null +++ b/backend/src/main/java/com/votogether/domain/alarm/controller/AlarmCommandController.java @@ -0,0 +1,32 @@ +package com.votogether.domain.alarm.controller; + +import com.votogether.domain.alarm.service.AlarmCommandService; +import com.votogether.domain.member.entity.Member; +import com.votogether.global.jwt.Auth; +import jakarta.validation.constraints.Positive; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PatchMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@Validated +@RequiredArgsConstructor +@RequestMapping("/alarms") +@RestController +public class AlarmCommandController implements AlarmCommandControllerDocs { + + private final AlarmCommandService alarmCommandService; + + @PatchMapping("/{id}") + public ResponseEntity readAlarm( + @PathVariable("id") @Positive(message = "알림 ID는 양수만 가능합니다.") final Long alarmId, + @Auth final Member loginMember + ) { + alarmCommandService.readAlarm(alarmId, loginMember); + return ResponseEntity.ok().build(); + } + +} diff --git a/backend/src/main/java/com/votogether/domain/alarm/controller/AlarmCommandControllerDocs.java b/backend/src/main/java/com/votogether/domain/alarm/controller/AlarmCommandControllerDocs.java new file mode 100644 index 000000000..d34b88102 --- /dev/null +++ b/backend/src/main/java/com/votogether/domain/alarm/controller/AlarmCommandControllerDocs.java @@ -0,0 +1,39 @@ +package com.votogether.domain.alarm.controller; + +import com.votogether.domain.member.entity.Member; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.constraints.Positive; +import org.springframework.http.ResponseEntity; + +@Tag(name = "알림 커맨드", description = "알림 커맨드 API") +public interface AlarmCommandControllerDocs { + + @Operation( + summary = "알림 읽기", + description = "알림을 읽을 수 있는 대상이라면 알림을 읽습니다." + ) + @ApiResponses({ + @ApiResponse( + responseCode = "200", + description = "알림 읽기 성공" + ), + @ApiResponse( + responseCode = "400", + description = "알림을 읽을 수 있는 대상이 아닌 경우" + ), + @ApiResponse( + responseCode = "404", + description = "알림이 존재하지 않은 경우" + ) + }) + ResponseEntity readAlarm( + @Parameter(description = "알림 ID", example = "1") + @Positive(message = "알림 ID는 양수만 가능합니다.") final Long alarmId, + final Member loginMember + ); + +} diff --git a/backend/src/test/java/com/votogether/domain/alarm/controller/AlarmCommandControllerTest.java b/backend/src/test/java/com/votogether/domain/alarm/controller/AlarmCommandControllerTest.java new file mode 100644 index 000000000..60a94406a --- /dev/null +++ b/backend/src/test/java/com/votogether/domain/alarm/controller/AlarmCommandControllerTest.java @@ -0,0 +1,81 @@ +package com.votogether.domain.alarm.controller; + +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.equalTo; +import static org.mockito.BDDMockito.any; +import static org.mockito.BDDMockito.anyLong; +import static org.mockito.BDDMockito.willDoNothing; + +import com.votogether.domain.alarm.service.AlarmCommandService; +import com.votogether.domain.member.entity.Member; +import com.votogether.test.ControllerTest; +import io.restassured.module.mockmvc.RestAssuredMockMvc; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.test.web.servlet.MockMvc; + +@WebMvcTest(AlarmCommandController.class) +class AlarmCommandControllerTest extends ControllerTest { + + @Autowired + MockMvc mockMvc; + + @MockBean + AlarmCommandService alarmCommandService; + + @BeforeEach + void setUp() { + RestAssuredMockMvc.mockMvc(mockMvc); + } + + @Nested + @DisplayName("알림을 읽을 시") + class ReadAlarm { + + @Test + @DisplayName("정상적인 요청이라면 200 응답을 반환한다.") + void readAlarm() throws Exception { + // given + mockingAuthArgumentResolver(); + willDoNothing().given(alarmCommandService).readAlarm(anyLong(), any(Member.class)); + + // when, then + RestAssuredMockMvc + .given().log().all() + .headers(HttpHeaders.AUTHORIZATION, BEARER_TOKEN) + .when().patch("/alarms/{id}", 1L) + .then().log().all() + .status(HttpStatus.OK); + } + + @ParameterizedTest + @ValueSource(longs = {-1, 0}) + @DisplayName("알림ID가 양수가 아니라면 400 응답을 반환한다.") + void negativeAlarmId(Long alarmId) throws Exception { + // given + mockingAuthArgumentResolver(); + willDoNothing().given(alarmCommandService).readAlarm(anyLong(), any(Member.class)); + + // when, then + RestAssuredMockMvc + .given().log().all() + .headers(HttpHeaders.AUTHORIZATION, BEARER_TOKEN) + .when().patch("/alarms/{id}", alarmId) + .then().log().all() + .status(HttpStatus.BAD_REQUEST) + .body("code", equalTo(201)) + .body("message", containsString("알림 ID는 양수만 가능합니다.")); + } + + } + +}