Skip to content

Commit

Permalink
[IDLE-400] 채용 공고 지원자 발생 시, 센터 관리자에게 알림을 발송한다.
Browse files Browse the repository at this point in the history
  • Loading branch information
wonjunYou committed Oct 3, 2024
1 parent d7fb9c4 commit df01ceb
Show file tree
Hide file tree
Showing 14 changed files with 218 additions and 37 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.swm.idle.application.applys.domain

import com.swm.idle.domain.applys.event.ApplyEvent
import org.springframework.context.ApplicationEventPublisher
import org.springframework.stereotype.Service

@Service
class CarerApplyEventPublisher(
private val eventPublisher: ApplicationEventPublisher,
) {

fun publish(applyEvent: ApplyEvent) {
eventPublisher.publishEvent(applyEvent)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ class CarerApplyService(
jobPostingId: UUID,
carerId: UUID,
applyMethodType: ApplyMethodType,
) {
carerApplyJpaRepository.save(
): Applys {
return carerApplyJpaRepository.save(
Applys(
jobPostingId = jobPostingId,
carerId = carerId,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,39 +1,65 @@
package com.swm.idle.application.applys.facade

import com.swm.idle.application.applys.domain.CarerApplyEventPublisher
import com.swm.idle.application.applys.domain.CarerApplyService
import com.swm.idle.application.common.security.getUserAuthentication
import com.swm.idle.application.jobposting.domain.JobPostingService
import com.swm.idle.application.notification.domain.DeviceTokenService
import com.swm.idle.application.user.carer.domain.CarerService
import com.swm.idle.domain.applys.event.ApplyEvent
import com.swm.idle.domain.applys.exception.ApplyException
import com.swm.idle.domain.jobposting.enums.ApplyMethodType
import io.github.oshai.kotlinlogging.KotlinLogging
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Propagation
import org.springframework.transaction.annotation.Transactional
import java.util.*

@Service
@Transactional(readOnly = true)
class CarerApplyFacadeService(
private val carerApplyService: CarerApplyService,
private val carerApplyEventPublisher: CarerApplyEventPublisher,
private val deviceTokenService: DeviceTokenService,
private val jobPostingService: JobPostingService,
private val carerService: CarerService,
) {

@Transactional
private val logger = KotlinLogging.logger { }

@Transactional(propagation = Propagation.REQUIRES_NEW)
fun createApply(
jobPostingId: UUID,
applyMethodType: ApplyMethodType,
) {
val carerId = getUserAuthentication().userId
val carer = getUserAuthentication().userId.let {
carerService.getById(it)
}
val deviceToken = deviceTokenService.findByUserId(carer.id)
val jobPosting = jobPostingService.getById(jobPostingId)

if (carerApplyService.existsByJobPostingIdAndCarerId(
jobPostingId = jobPostingId,
carerId = carerId,
carerId = carer.id,
)
) {
throw ApplyException.AlreadyApplied()
}

carerApplyService.create(
jobPostingId = jobPostingId,
carerId = carerId,
applyMethodType = applyMethodType,
)
carerApplyService.create(jobPostingId, carer.id, applyMethodType)

deviceToken?.let {
carerApplyEventPublisher.publish(
ApplyEvent.createApplyEvent(
deviceToken = deviceToken,
jobPosting = jobPosting,
carer = carer,
)
)
} ?: run {
logger.warn { "${carer.id} 요양 보호사의 device Token이 존재하지 않아 알림이 발송되지 않았습니다." }
}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ class DeviceTokenService(
return deviceTokenJpaRepository.findByDeviceToken(deviceToken)
}

fun findByUserId(userId: UUID): DeviceToken? {
return deviceTokenJpaRepository.findByUserId(userId)
}

@Transactional
fun updateDeviceTokenUserId(
deviceToken: DeviceToken,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.swm.idle.domain.applys.event

import com.swm.idle.domain.jobposting.entity.jpa.JobPosting
import com.swm.idle.domain.notification.jpa.DeviceToken
import com.swm.idle.domain.user.carer.entity.jpa.Carer

data class ApplyEvent(
val deviceToken: DeviceToken,
val jobPosting: JobPosting,
val carer: Carer,
) {

companion object {

fun createApplyEvent(
deviceToken: DeviceToken,
jobPosting: JobPosting,
carer: Carer,
): ApplyEvent {
return ApplyEvent(deviceToken, jobPosting, carer)
}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,6 @@ interface DeviceTokenJpaRepository : JpaRepository<DeviceToken, UUID> {

fun deleteByDeviceToken(deviceToken: String)

fun findByUserId(userId: UUID): DeviceToken?

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package com.swm.idle.domain.user.common.enum

enum class GenderType {
MAN,
WOMAN;
}
enum class GenderType(
val value: String,
) {

MAN("남성"),
WOMAN("여성");
}
1 change: 1 addition & 0 deletions idle-infrastructure/fcm/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ bootJar.enabled = false
jar.enabled = true

dependencies {
implementation(project(":idle-domain"))
implementation(project(":idle-support:common"))

implementation(rootProject.libs.fcm)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.swm.idle.infrastructure.fcm.applys.listener

import com.swm.idle.domain.applys.event.ApplyEvent
import com.swm.idle.infrastructure.fcm.applys.service.CarerApplyEventService
import org.springframework.context.event.EventListener
import org.springframework.stereotype.Component

@Component

class CarerApplyEventListener(
private val carerApplyEventService: CarerApplyEventService,
) {

@EventListener
fun handleCarerApplyEvent(applyEvent: ApplyEvent) {
carerApplyEventService.send(applyEvent)
}

}

Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package com.swm.idle.infrastructure.fcm.applys.service

import com.google.firebase.messaging.Message
import com.google.firebase.messaging.Notification
import com.swm.idle.domain.applys.event.ApplyEvent
import com.swm.idle.domain.user.common.vo.BirthYear
import com.swm.idle.infrastructure.fcm.common.client.FcmClient
import com.swm.idle.infrastructure.fcm.common.enums.DestinationType
import org.springframework.stereotype.Component

@Component
class CarerApplyEventService(
private val fcmClient: FcmClient,
) {

fun send(applyEvent: ApplyEvent) {
createMessage(applyEvent).also {
fcmClient.send(it)
}
}

private fun createApplyNotification(applyEvent: ApplyEvent): Notification {
return Notification.builder()
.setTitle("${applyEvent.carer.name} 님이 공고에 지원하였습니다.")
.setBody(createBodyMessage(applyEvent))
.build()
}

private fun createBodyMessage(applyEvent: ApplyEvent): String? {
val filteredLotNumberAddress = applyEvent.jobPosting.lotNumberAddress.split(" ")
.take(3)
.joinToString(" ")

return "$filteredLotNumberAddress " +
"${applyEvent.jobPosting.careLevel}등급 " +
"${BirthYear.calculateAge(applyEvent.jobPosting.birthYear)}" +
applyEvent.jobPosting.gender.value
}

private fun createMessage(applyEvent: ApplyEvent): Message {
val applyNotification = createApplyNotification(applyEvent)

return Message.builder()
.setToken(applyEvent.deviceToken.deviceToken)
.setNotification(applyNotification)
.putData("destination", DestinationType.APPLICANTS.toString())
.putData("jobPostingId", applyEvent.jobPosting.id.toString())
.build();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.swm.idle.infrastructure.fcm.common.client

import com.google.firebase.messaging.FirebaseMessaging
import com.google.firebase.messaging.Message
import org.springframework.stereotype.Component

@Component
class FcmClient {

fun send(message: Message) {
firebase.sendAsync(message)
}

companion object {

val firebase: FirebaseMessaging = FirebaseMessaging.getInstance()
}

}
Original file line number Diff line number Diff line change
@@ -1,29 +1,9 @@
package com.swm.idle.infrastructure.fcm.common.config

import com.google.auth.oauth2.GoogleCredentials
import com.google.firebase.FirebaseApp
import com.google.firebase.FirebaseOptions
import jakarta.annotation.PostConstruct
import org.springframework.beans.factory.annotation.Value
import org.springframework.context.annotation.ComponentScan
import org.springframework.context.annotation.Configuration
import org.springframework.core.io.ClassPathResource

@Configuration
class FcmConfig {

@Value("\${firebase.json.path}")
lateinit var firebaseConfigJsonPath: String

@PostConstruct
fun initializeFirebaseApp() {
val googleCredentials =
GoogleCredentials.fromStream(ClassPathResource(firebaseConfigJsonPath).inputStream)

val fireBaseOptions = FirebaseOptions.builder()
.setCredentials(googleCredentials)
.build()

FirebaseApp.initializeApp(fireBaseOptions)
}

@ComponentScan(basePackages = ["com.swm.idle.infrastructure.fcm"])
interface FcmConfig {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.swm.idle.infrastructure.fcm.common.config

import com.google.auth.oauth2.GoogleCredentials
import com.google.firebase.FirebaseApp
import com.google.firebase.FirebaseOptions
import jakarta.annotation.PostConstruct
import org.springframework.beans.factory.annotation.Value
import org.springframework.context.annotation.Configuration
import org.springframework.core.io.ClassPathResource

@Configuration
class FirebaseConfig {

@Value("\${firebase.json.path}")
lateinit var firebaseConfigJsonPath: String

@PostConstruct
fun initializeFirebaseApp() {
val googleCredentials =
GoogleCredentials.fromStream(ClassPathResource(firebaseConfigJsonPath).inputStream)

val fireBaseOptions = FirebaseOptions.builder()
.setCredentials(googleCredentials)
.build()

FirebaseApp.initializeApp(fireBaseOptions)
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.swm.idle.infrastructure.fcm.common.enums

enum class DestinationType {
APPLICANTS
}

0 comments on commit df01ceb

Please sign in to comment.