From 2f4e0f30a4e1f02d69500b97af73dde79f1efca0 Mon Sep 17 00:00:00 2001 From: Haebin Date: Sun, 5 Jan 2025 21:27:15 +0900 Subject: [PATCH] feat: unclassified Vaccination Discord Webhook --- API-CONFIG | 2 +- build.gradle.kts | 3 + .../kotlin/kr/co/vacgom/api/TestController.kt | 24 +++++++ .../api/global/discord/DiscordSender.kt | 65 +++++++++++++++++++ .../api/global/discord/RestTemplateConfig.kt | 14 ++++ .../api/user/repository/UserRepository.kt | 1 + .../user/repository/UserRepositoryAdapter.kt | 6 +- .../vaccine/application/VaccinationService.kt | 7 +- 8 files changed, 118 insertions(+), 4 deletions(-) create mode 100644 src/main/kotlin/kr/co/vacgom/api/TestController.kt create mode 100644 src/main/kotlin/kr/co/vacgom/api/global/discord/DiscordSender.kt create mode 100644 src/main/kotlin/kr/co/vacgom/api/global/discord/RestTemplateConfig.kt diff --git a/API-CONFIG b/API-CONFIG index e3e2737..12cbc6f 160000 --- a/API-CONFIG +++ b/API-CONFIG @@ -1 +1 @@ -Subproject commit e3e27372bce78ec6e2bd0acfc0c2b5fad6c043f3 +Subproject commit 12cbc6fe5d4644e60c27f94a3954730ae8398fab diff --git a/build.gradle.kts b/build.gradle.kts index a79f74b..e6dbe59 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -76,6 +76,9 @@ dependencies { implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.1") annotationProcessor("org.springframework.boot:spring-boot-configuration-processor") + + // discord + implementation("dev.kord:kord-core:0.15.0") } kotlin { diff --git a/src/main/kotlin/kr/co/vacgom/api/TestController.kt b/src/main/kotlin/kr/co/vacgom/api/TestController.kt new file mode 100644 index 0000000..3b1bdec --- /dev/null +++ b/src/main/kotlin/kr/co/vacgom/api/TestController.kt @@ -0,0 +1,24 @@ +package kr.co.vacgom.api + +import kr.co.vacgom.api.global.presentation.GlobalPath.BASE_V3 +import kr.co.vacgom.api.user.application.UserTokenService +import kr.co.vacgom.api.user.repository.UserRepository +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController + +@RestController +@RequestMapping(BASE_V3 + "/TEST") +class TestController( + private val userRepository: UserRepository, + private val userTokenService: UserTokenService +) { + + @PostMapping + fun test(): ResponseEntity { + val user = userRepository.findAll().get(0) + val accessToken = userTokenService.createAccessToken(user.id, user.role) + return ResponseEntity.ok(accessToken) + } +} diff --git a/src/main/kotlin/kr/co/vacgom/api/global/discord/DiscordSender.kt b/src/main/kotlin/kr/co/vacgom/api/global/discord/DiscordSender.kt new file mode 100644 index 0000000..80984da --- /dev/null +++ b/src/main/kotlin/kr/co/vacgom/api/global/discord/DiscordSender.kt @@ -0,0 +1,65 @@ +package kr.co.vacgom.api.global.discord + +import com.fasterxml.jackson.databind.ObjectMapper +import kr.co.vacgom.api.baby.domain.Baby +import kr.co.vacgom.api.vaccine.domain.UnclassifiedVaccination +import org.springframework.beans.factory.annotation.Value +import org.springframework.http.HttpEntity +import org.springframework.http.HttpHeaders +import org.springframework.http.MediaType +import org.springframework.stereotype.Component +import org.springframework.web.client.RestTemplate +import java.time.LocalDateTime +import java.time.format.DateTimeFormatter + +@Component +class DiscordSender( + @Value("\${discord.deployWebhookURL}") + private val webhookURL: String, + + @Value("\${discord.welcomeWebhookURL}") + private val welcomeURL: String, + + private val objectMapper: ObjectMapper, + + private val restTemplate: RestTemplate +) { + fun sendVaccinationError( + baby: Baby, + unclassifiedVaccination: UnclassifiedVaccination + ) { + val headers = HttpHeaders() + headers.contentType = MediaType.APPLICATION_JSON + + val now = LocalDateTime.now() + val formatter = DateTimeFormatter.ofPattern("yyyy년 MM월 dd일 HH시 mm분 ss초") + val formattedNow = now.format(formatter) + + val embeds = mapOf( + "title" to "**[ \uD83D\uDEA8 긴급 \uD83D\uDEA8 ] ERR-001** 미분류 백신 추가 필요", + "description" to "**미분류 백신** : ${unclassifiedVaccination.name}\n\n" + + "**요청시간** : " + formattedNow + "\n\n" + + "**LOG**\n\n" + + "```json\n{\n" + + "\t\"id\" : ${unclassifiedVaccination.id},\n" + + "\t\"name\" : ${unclassifiedVaccination.name},\n" + + "\t\"doseRound\" : ${unclassifiedVaccination.doseRound},\n" + + "\t\"doseRoundDescription\" : ${unclassifiedVaccination.doseRoundDescription},\n" + + "\t\"vaccinatedAt\" : ${unclassifiedVaccination.vaccinatedAt},\n" + + "\t\"facility\" : ${unclassifiedVaccination.facility},\n" + + "\t\"manufacturer\" : ${unclassifiedVaccination.manufacturer},\n" + + "\t\"productName\" : ${unclassifiedVaccination.productName},\n" + + "\t\"lotNumber\" : ${unclassifiedVaccination.lotNumber},\n" + + "\t\"babyId\" : ${unclassifiedVaccination.baby.id}\n}```", + "color" to "15548997" + ) + val payload = mapOf( + "content" to null, + "embeds" to listOf(embeds) + ) + + val jsonPayload = objectMapper.writeValueAsString(payload) + val entity = HttpEntity(jsonPayload, headers) + restTemplate.postForLocation(webhookURL, entity) + } +} diff --git a/src/main/kotlin/kr/co/vacgom/api/global/discord/RestTemplateConfig.kt b/src/main/kotlin/kr/co/vacgom/api/global/discord/RestTemplateConfig.kt new file mode 100644 index 0000000..974154a --- /dev/null +++ b/src/main/kotlin/kr/co/vacgom/api/global/discord/RestTemplateConfig.kt @@ -0,0 +1,14 @@ +package kr.co.vacgom.api.global.discord + +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.web.client.RestTemplate + +@Configuration +class RestTemplateConfig { + + @Bean + fun restTemplate(): RestTemplate { + return RestTemplate() + } +} diff --git a/src/main/kotlin/kr/co/vacgom/api/user/repository/UserRepository.kt b/src/main/kotlin/kr/co/vacgom/api/user/repository/UserRepository.kt index b3ed1f6..315da23 100644 --- a/src/main/kotlin/kr/co/vacgom/api/user/repository/UserRepository.kt +++ b/src/main/kotlin/kr/co/vacgom/api/user/repository/UserRepository.kt @@ -9,4 +9,5 @@ interface UserRepository { fun findBySocialId(socialId: String): User? fun findById(userId: UUID): User? fun deleteById(userId: UUID) + fun findAll(): List } diff --git a/src/main/kotlin/kr/co/vacgom/api/user/repository/UserRepositoryAdapter.kt b/src/main/kotlin/kr/co/vacgom/api/user/repository/UserRepositoryAdapter.kt index 9291b4e..8f2c81e 100644 --- a/src/main/kotlin/kr/co/vacgom/api/user/repository/UserRepositoryAdapter.kt +++ b/src/main/kotlin/kr/co/vacgom/api/user/repository/UserRepositoryAdapter.kt @@ -8,7 +8,7 @@ import java.util.* @Repository class UserRepositoryAdapter( private val userJpaRepository: UserJpaRepository -): UserRepository { +) : UserRepository { override fun save(user: User): User { return userJpaRepository.save(user) } @@ -24,4 +24,8 @@ class UserRepositoryAdapter( override fun deleteById(userId: UUID) { userJpaRepository.deleteById(userId) } + + override fun findAll(): List { + return userJpaRepository.findAll() + } } diff --git a/src/main/kotlin/kr/co/vacgom/api/vaccine/application/VaccinationService.kt b/src/main/kotlin/kr/co/vacgom/api/vaccine/application/VaccinationService.kt index 6ec8ee5..0957726 100644 --- a/src/main/kotlin/kr/co/vacgom/api/vaccine/application/VaccinationService.kt +++ b/src/main/kotlin/kr/co/vacgom/api/vaccine/application/VaccinationService.kt @@ -1,6 +1,7 @@ package kr.co.vacgom.api.vaccine.application import kr.co.vacgom.api.baby.repository.BabyRepository +import kr.co.vacgom.api.global.discord.DiscordSender import kr.co.vacgom.api.global.exception.error.BusinessException import kr.co.vacgom.api.vaccine.domain.UnclassifiedVaccination import kr.co.vacgom.api.vaccine.domain.Vaccination @@ -17,7 +18,8 @@ class VaccinationService( private val unclassifiedVaccinationRepository: UnclassifiedVaccinationRepository, private val vaccinationRepository: VaccinationRepository, private val vaccineRepository: VaccineRepository, - private val babyRepository: BabyRepository + private val babyRepository: BabyRepository, + private val discordSender: DiscordSender ) { fun createVaccinations(request: VaccinationDto.Request.Create) { @@ -53,7 +55,8 @@ class VaccinationService( baby = baby ) - unclassifiedVaccinationRepository.save(unclassifiedVaccination) + val savedUnclassifiedVaccination = unclassifiedVaccinationRepository.save(unclassifiedVaccination) + discordSender.sendVaccinationError(baby, savedUnclassifiedVaccination) } } }