diff --git a/pothole-core/src/main/java/pothole_solution/core/global/util/alarm/slack/SlackMessageFormatter.java b/pothole-core/src/main/java/pothole_solution/core/global/util/alarm/slack/SlackMessageFormatter.java index dd65ad4..dcb9131 100644 --- a/pothole-core/src/main/java/pothole_solution/core/global/util/alarm/slack/SlackMessageFormatter.java +++ b/pothole-core/src/main/java/pothole_solution/core/global/util/alarm/slack/SlackMessageFormatter.java @@ -5,7 +5,10 @@ import org.springframework.core.io.ClassPathResource; import pothole_solution.core.global.util.alarm.slack.dto.SlkPrInfoSlkMsgFmtrDto; +import jakarta.servlet.http.HttpServletRequest; import java.io.IOException; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.List; @@ -90,4 +93,68 @@ private SlkPrInfoSlkMsgFmtrDto getPRInfo() { .build(); } } + + public List buildStartDetectionMessage(LocalDateTime startupTime, HttpServletRequest request) { + List layoutBlocks = new ArrayList<>(); + + leaveSpace(layoutBlocks); + + // header + layoutBlocks.add(header(headerBlockBuilder -> headerBlockBuilder.text(plainText(":newspaper: 포트홀 탐지 차량 알림 :newspaper:")))); + layoutBlocks.add(divider()); + + // body + + // title + layoutBlocks.add(section(section -> section.text(markdownText(":placard: *Title*")))); + layoutBlocks.add(section(section -> section.text(markdownText("포트홀 탐지 차량 출발")))); + layoutBlocks.add(divider()); + + // time + String time = startupTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); + layoutBlocks.add(section(section -> section.text(markdownText(":placard: *시작 시간*")))); + layoutBlocks.add(section(section -> section.text(markdownText(time)))); + layoutBlocks.add(divider()); + + // time + layoutBlocks.add(section(section -> section.text(markdownText(":placard: *탐지 차량 IP*")))); + layoutBlocks.add(section(section -> section.text(markdownText(getClientIp(request))))); + layoutBlocks.add(divider()); + + // time + String statusEmoji = ":white_check_mark:"; + layoutBlocks.add(section(section -> section.text(markdownText("*성공 여부* | " + statusEmoji)))); + layoutBlocks.add(section(section -> section.text(markdownText("*담당자* | " + "신채호")))); + + leaveSpace(layoutBlocks); + leaveSpace(layoutBlocks); + + return layoutBlocks; + } + + private String getClientIp(HttpServletRequest request) { + String ip = request.getHeader("X-Forwarded-For"); + + if (ip == null || ip.length() == 0) { + ip = request.getHeader("Proxy-Client-IP"); + } + + if (ip == null || ip.length() == 0) { + ip = request.getHeader("WL-Proxy-Client-IP"); + } + + if (ip == null || ip.length() == 0) { + ip = request.getHeader("HTTP_CLIENT_IP"); + } + + if (ip == null || ip.length() == 0) { + ip = request.getHeader("HTTP_X_FORWARDED_FOR"); + } + + if (ip == null || ip.length() == 0) { + ip = request.getRemoteAddr(); + } + + return ip; + } } diff --git a/pothole-core/src/main/java/pothole_solution/core/global/util/alarm/slack/constant/SlackConstant.java b/pothole-core/src/main/java/pothole_solution/core/global/util/alarm/slack/constant/SlackConstant.java index 7aed315..50c1dd9 100644 --- a/pothole-core/src/main/java/pothole_solution/core/global/util/alarm/slack/constant/SlackConstant.java +++ b/pothole-core/src/main/java/pothole_solution/core/global/util/alarm/slack/constant/SlackConstant.java @@ -11,6 +11,7 @@ public class SlackConstant { public static final String WORKER_SERVER = "Worker"; public static final String POTHOLE_SERVER_DEPLOY_PREVIEW_MSG = ":loudspeaker: 포트홀 서버가 배포되었습니다. 배포된 내용을 확인해주세요."; + public static final String POTHOLE_DETECTION_START_PREVIEW_MSG = ":loudspeaker: 포트홀 탐지 차량이 출발하였습니다."; public static final String FAILURE_STARTUP_TIME = "0.000"; diff --git a/pothole-core/src/main/java/pothole_solution/core/infra/config/SecurityConfig.java b/pothole-core/src/main/java/pothole_solution/core/infra/config/SecurityConfig.java index 7743089..c36f4e8 100644 --- a/pothole-core/src/main/java/pothole_solution/core/infra/config/SecurityConfig.java +++ b/pothole-core/src/main/java/pothole_solution/core/infra/config/SecurityConfig.java @@ -36,9 +36,11 @@ SecurityFilterChain filterChain(HttpSecurity http) throws Exception { .maximumSessions(2) ) .authorizeHttpRequests(authorizeRequest -> authorizeRequest - .requestMatchers( + .requestMatchers( // 인증 예외 처리 AntPathRequestMatcher.antMatcher("/pothole/v1/auth/**/join"), AntPathRequestMatcher.antMatcher("/pothole/v1/auth/**/login")).permitAll() + .requestMatchers( // 포트홀 탐지 차량 예외 처리 + AntPathRequestMatcher.antMatcher("/pothole/v1/manager/detection/start")).permitAll() .requestMatchers( AntPathRequestMatcher.antMatcher("/pothole/v1/manager/**")).hasRole("MANAGER") .requestMatchers( diff --git a/pothole-manager-api/src/main/java/pothole_solution/manager/health/DetectionCheckController.java b/pothole-manager-api/src/main/java/pothole_solution/manager/health/DetectionCheckController.java new file mode 100644 index 0000000..5901b8d --- /dev/null +++ b/pothole-manager-api/src/main/java/pothole_solution/manager/health/DetectionCheckController.java @@ -0,0 +1,42 @@ +package pothole_solution.manager.health; + +import com.slack.api.model.block.LayoutBlock; +import jakarta.servlet.http.HttpServletRequest; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +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 pothole_solution.core.global.util.alarm.slack.SlackMessageFormatter; +import pothole_solution.core.global.util.alarm.slack.SlackService; +import pothole_solution.core.global.util.response.BaseResponse; +import pothole_solution.manager.health.dto.RespHlthChkDto; + +import java.time.LocalDateTime; +import java.util.List; + +import static pothole_solution.core.global.util.alarm.slack.constant.SlackConstant.*; + +@Slf4j +@RestController +@RequiredArgsConstructor +@RequestMapping("/pothole/v1/manager/detection") +public class DetectionCheckController { + + private final SlackService slackService; + + @GetMapping("/start") + public BaseResponse startDetection(@RequestParam(name = "alarm", required = false) Boolean alarm, + HttpServletRequest request) { + log.info("pothole detection start"); + + if (alarm != null && alarm) { + List layoutBlocks = new SlackMessageFormatter() + .buildStartDetectionMessage(LocalDateTime.now(), request); + slackService.sendMessage(POTHOLE_SERVER_DEPLOY, POTHOLE_DETECTION_START_PREVIEW_MSG, layoutBlocks); + } + + return new BaseResponse<>(new RespHlthChkDto(true)); + } +} diff --git a/pothole-manager-api/src/main/java/pothole_solution/manager/health/dto/RespHlthChkDto.java b/pothole-manager-api/src/main/java/pothole_solution/manager/health/dto/RespHlthChkDto.java new file mode 100644 index 0000000..9340b0d --- /dev/null +++ b/pothole-manager-api/src/main/java/pothole_solution/manager/health/dto/RespHlthChkDto.java @@ -0,0 +1,10 @@ +package pothole_solution.manager.health.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class RespHlthChkDto { + private Boolean health; +}