diff --git a/build.gradle b/build.gradle index 758ad7da..4860a110 100644 --- a/build.gradle +++ b/build.gradle @@ -60,6 +60,9 @@ dependencies { runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.5' runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.11.5' + implementation group: 'org.json', name: 'json', version: '20231013' + + } tasks.named('test') { diff --git a/src/main/java/com/prgrms/catchtable/common/NotificationContent.java b/src/main/java/com/prgrms/catchtable/common/NotificationContent.java new file mode 100644 index 00000000..06af80c9 --- /dev/null +++ b/src/main/java/com/prgrms/catchtable/common/NotificationContent.java @@ -0,0 +1,20 @@ +package com.prgrms.catchtable.common; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@Getter +public enum NotificationContent { + RESERVATION_COMPLETED("예약이 완료되었습니다"), + RESERVATION_ONE_HOUR_LEFT("예약 시간 1시간 전입니다."), + RESERVATION_TIME_TO_ENTER("예약시간이 되었습니다"), + WAITING_REGISTER_COMPLETED("웨이팅 등록이 완료되었습니다"), + WAITING_RANK_THIRD("웨이팅 순서가 3번째가 되었습니다"), + WAITING_TIME_TO_ENTER("웨이팅이 끝났습니다. 입장 부탁드립니다."), + WAITING_CANCELLED_AUTOMATICALLY("웨이팅이 자동으로 취소되었습니다."); + + private final String message; + + +} diff --git a/src/main/java/com/prgrms/catchtable/common/exception/ErrorCode.java b/src/main/java/com/prgrms/catchtable/common/exception/ErrorCode.java index a0b3afe4..321ac07c 100644 --- a/src/main/java/com/prgrms/catchtable/common/exception/ErrorCode.java +++ b/src/main/java/com/prgrms/catchtable/common/exception/ErrorCode.java @@ -17,6 +17,7 @@ public enum ErrorCode { NOT_EXIST_RESERVATION("존재하지 않는 예약입니다"), EXCEED_PEOPLE_COUNT("예약인원이 해당 시간의 남은 수용가능 인원 수를 초과했습니다."), ALREADY_COMPLETED_RESERVATION("이미 예약 상태인 예약입니다."), + SLACK_ID_IS_WRONG("요청한 슬랙 Id를 찾을 수 없거나 잘못 되었습니다"), CAN_NOT_COMPLETE_WAITING("입장 처리가 불가한 대기 상태입니다."), EXISTING_MEMBER_WAITING("이미 회원이 웨이팅 중인 가게가 존재합니다."), @@ -30,9 +31,9 @@ public enum ErrorCode { SHOP_NOT_RUNNING("가게가 영업시간이 아닙니다."), INTERNAL_SERVER_ERROR("내부 서버 오류입니다."), + ALREADY_EXIST_OWNER("이미 존재하는 점주입니다"), BAD_REQUEST_EMAIL_OR_PASSWORD("이메일 혹은 비밀번호를 확인해주세요"), BAD_REQUEST_INPUT_GENDER_TYPE("성별 타입을 양식대로 입력해주세요"); - private final String message; } \ No newline at end of file diff --git a/src/main/java/com/prgrms/catchtable/notification/controller/NotificationController.java b/src/main/java/com/prgrms/catchtable/notification/controller/NotificationController.java new file mode 100644 index 00000000..07007c94 --- /dev/null +++ b/src/main/java/com/prgrms/catchtable/notification/controller/NotificationController.java @@ -0,0 +1,20 @@ +package com.prgrms.catchtable.notification.controller; + +import com.prgrms.catchtable.notification.dto.request.SendMessageRequest; +import com.prgrms.catchtable.notification.service.NotificationService; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequiredArgsConstructor +public class NotificationController { + + private final NotificationService notificationService; + + @GetMapping("/test") + public void test(@RequestBody SendMessageRequest request) { + notificationService.sendMessageToMemberAndSave(request); + } +} diff --git a/src/main/java/com/prgrms/catchtable/notification/domain/NotificationOwner.java b/src/main/java/com/prgrms/catchtable/notification/domain/NotificationOwner.java index 4f4c3935..4a3885e5 100644 --- a/src/main/java/com/prgrms/catchtable/notification/domain/NotificationOwner.java +++ b/src/main/java/com/prgrms/catchtable/notification/domain/NotificationOwner.java @@ -36,7 +36,8 @@ public class NotificationOwner extends BaseEntity { private Owner owner; @Builder - public NotificationOwner(String message) { + public NotificationOwner(Owner owner, String message) { + this.owner = owner; this.message = message; } } diff --git a/src/main/java/com/prgrms/catchtable/notification/dto/request/SendMessageRequest.java b/src/main/java/com/prgrms/catchtable/notification/dto/request/SendMessageRequest.java new file mode 100644 index 00000000..7c2034f7 --- /dev/null +++ b/src/main/java/com/prgrms/catchtable/notification/dto/request/SendMessageRequest.java @@ -0,0 +1,7 @@ +package com.prgrms.catchtable.notification.dto.request; + +import com.prgrms.catchtable.common.NotificationContent; + +public record SendMessageRequest(NotificationContent content) { + +} diff --git a/src/main/java/com/prgrms/catchtable/notification/repository/NotificationMemberRepository.java b/src/main/java/com/prgrms/catchtable/notification/repository/NotificationMemberRepository.java index e9c5b5a7..44598e0e 100644 --- a/src/main/java/com/prgrms/catchtable/notification/repository/NotificationMemberRepository.java +++ b/src/main/java/com/prgrms/catchtable/notification/repository/NotificationMemberRepository.java @@ -1,8 +1,11 @@ package com.prgrms.catchtable.notification.repository; +import com.prgrms.catchtable.member.domain.Member; import com.prgrms.catchtable.notification.domain.NotificationMember; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; public interface NotificationMemberRepository extends JpaRepository { + Optional findByMember(Member member); } diff --git a/src/main/java/com/prgrms/catchtable/notification/repository/NotificationOwnerRepository.java b/src/main/java/com/prgrms/catchtable/notification/repository/NotificationOwnerRepository.java index bca2921d..eb840345 100644 --- a/src/main/java/com/prgrms/catchtable/notification/repository/NotificationOwnerRepository.java +++ b/src/main/java/com/prgrms/catchtable/notification/repository/NotificationOwnerRepository.java @@ -1,8 +1,11 @@ package com.prgrms.catchtable.notification.repository; import com.prgrms.catchtable.notification.domain.NotificationOwner; +import com.prgrms.catchtable.owner.domain.Owner; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; public interface NotificationOwnerRepository extends JpaRepository { + Optional findByOwner(Owner owner); } diff --git a/src/main/java/com/prgrms/catchtable/notification/service/NotificationService.java b/src/main/java/com/prgrms/catchtable/notification/service/NotificationService.java new file mode 100644 index 00000000..eb862c67 --- /dev/null +++ b/src/main/java/com/prgrms/catchtable/notification/service/NotificationService.java @@ -0,0 +1,137 @@ +package com.prgrms.catchtable.notification.service; + +import static com.prgrms.catchtable.common.exception.ErrorCode.SLACK_ID_IS_WRONG; +import static org.springframework.http.HttpMethod.GET; +import static org.springframework.http.HttpMethod.POST; + +import com.prgrms.catchtable.common.exception.custom.BadRequestCustomException; +import com.prgrms.catchtable.member.domain.Member; +import com.prgrms.catchtable.member.repository.MemberRepository; +import com.prgrms.catchtable.notification.domain.NotificationMember; +import com.prgrms.catchtable.notification.domain.NotificationOwner; +import com.prgrms.catchtable.notification.dto.request.SendMessageRequest; +import com.prgrms.catchtable.notification.repository.NotificationMemberRepository; +import com.prgrms.catchtable.notification.repository.NotificationOwnerRepository; +import com.prgrms.catchtable.owner.domain.Owner; +import com.prgrms.catchtable.owner.repository.OwnerRepository; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.json.JSONObject; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +@Service +@RequiredArgsConstructor +@Slf4j +public class NotificationService { + + @Value("${slack.token}") + private String slackToken; + + private final NotificationMemberRepository notificationMemberRepository; + private final NotificationOwnerRepository notificationOwnerRepository; + private final MemberRepository memberRepository; // 추후 삭제 예정 + private final OwnerRepository ownerRepository; // 추후 삭제 예정 + private JSONObject jsonObject; + + public void sendMessageToMemberAndSave(SendMessageRequest request) { + String url = "https://slack.com/api/chat.postMessage"; // slack 메세지를 보내도록 요청하는 Slack API + // member 예제 데이터 + Member member = Member.builder() + .email("dlswns661035@gmail.com") // 이 부분 이메일 바꿔서 하면 해당 이메일의 슬랙 개인으로 dm 보냄 + .build(); + + String email = member.getEmail(); + String message = request.content().getMessage(); + String slackId = getSlackIdByEmail(email); // 이메일을 통해 사용자의 슬랙 고유 ID 추출 + + requestToSendMessage(slackId, message); // 알림 요청 보내는 함수 호출 + + NotificationMember notification = NotificationMember.builder() + .member(member) + .message(message) + .build(); + memberRepository.save(member); // 추후 삭제 예정 + notificationMemberRepository.save(notification); // 해당 사용자의 알림 생성 후 저장 + + } + + public void sendMessageToOwnerAndSave(SendMessageRequest request) { + String url = "https://slack.com/api/chat.postMessage"; // slack 메세지를 보내도록 요청하는 Slack API + //Owner 예제 데이터 + Owner owner = Owner.builder() + .email("dlswns661035@gmail.com") // 이 부분 이메일 바꿔서 하면 해당 이메일의 슬랙 개인으로 dm 보냄 + .build(); + + String email = owner.getEmail(); + String message = request.content().getMessage(); + String slackId = getSlackIdByEmail(email); + + requestToSendMessage(slackId, message); + + NotificationOwner notification = NotificationOwner.builder() + .owner(owner) + .message(message) + .build(); + ownerRepository.save(owner); //추후 삭제 예정 + notificationOwnerRepository.save(notification); + } + + private void requestToSendMessage(String slackId, String message) { + String url = "https://slack.com/api/chat.postMessage"; + + // 헤더에 캐치테이블 클론 슬랙 토큰 삽입 + HttpHeaders headers = new HttpHeaders(); + headers.add("Authorization", "Bearer " + slackToken); + headers.add("Content-type", "application/json; charset=utf-8"); + + JSONObject jsonObject = new JSONObject(); + jsonObject.put("channel", slackId); // 채널 필드에 사용자의 슬랙 고유 ID + jsonObject.put("text", message); // 메세지 필드에 메세지 + String body = jsonObject.toString(); + + HttpEntity requestEntity = new HttpEntity<>(body, headers); + RestTemplate restTemplate = new RestTemplate(); + + ResponseEntity response = restTemplate.exchange( + url, + POST, + requestEntity, + String.class + );// post로 위에서 만든 Json body 전송 요청 + + jsonObject = new JSONObject(response.getBody()); + String result = jsonObject.get("ok").toString(); + + if (result.equals("false")) { // 알림 요청 보낸 후 응답의 ok필드 값이 false면 슬랙아이디가 잘못되었다는 것 + throw new BadRequestCustomException(SLACK_ID_IS_WRONG); + } + + // ok 필드값이 true면 알림 전송 완료 된것임 + } + + public String getSlackIdByEmail(String email) { + String url = "https://slack.com/api/users.lookupByEmail?email=".concat(email); + + HttpHeaders headers = new HttpHeaders(); + headers.add("Authorization", "Bearer " + slackToken); + headers.add("Content-type", "application/x-www-form-urlencoded"); + + RestTemplate restTemplate = new RestTemplate(); + HttpEntity requestEntity = new HttpEntity<>(headers); + ResponseEntity responseEntity = restTemplate.exchange( + url, + GET, + requestEntity, + String.class + ); + jsonObject = new JSONObject(responseEntity.getBody()); + JSONObject profile = jsonObject.getJSONObject("user"); + + return profile.get("id").toString(); + } +} diff --git a/src/test/resources/application.yaml b/src/test/resources/application.yaml index 1beefa13..fdaaf576 100644 --- a/src/test/resources/application.yaml +++ b/src/test/resources/application.yaml @@ -44,4 +44,6 @@ jwt: logging.level: org.hibernate.SQL: debug org.hibernate.orm.jdbc.bind: trace +slack: + token: xoxb-6433151143155-6426645660710-QosE3VDLJM62hLgSISYqLTUu