Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@ import uk.gov.justice.digital.hmpps.officialvisitsapi.repository.PrisonVisitSlot
import uk.gov.justice.digital.hmpps.officialvisitsapi.repository.PrisonerVisitedRepository
import uk.gov.justice.digital.hmpps.officialvisitsapi.service.auditing.AuditingService
import uk.gov.justice.digital.hmpps.officialvisitsapi.service.auditing.auditVisitCreateEvent
import uk.gov.justice.digital.hmpps.officialvisitsapi.service.events.outbound.Source
import uk.gov.justice.digital.hmpps.officialvisitsapi.service.metrics.MetricsEvents
import uk.gov.justice.digital.hmpps.officialvisitsapi.service.metrics.MetricsService
import uk.gov.justice.digital.hmpps.officialvisitsapi.service.metrics.VisitMetricInfo
import uk.gov.justice.digital.hmpps.officialvisitsapi.service.metrics.VisitorMetricInfo
import uk.gov.justice.digital.hmpps.officialvisitsapi.service.slotavailability.AvailableSlotService
import uk.gov.justice.digital.hmpps.officialvisitsapi.service.slotavailability.AvailableSlotSpecification
import uk.gov.justice.digital.hmpps.officialvisitsapi.service.slotavailability.AvailableSlotSpecificationFactory
Expand Down Expand Up @@ -106,6 +108,20 @@ class OfficialVisitCreateService(
)
},
)
}.also {
it.visitorAndContactIds.forEach { value ->
metricsService.send(
MetricsEvents.ADD_VISITOR,
VisitorMetricInfo(
source = Source.DPS,
username = user.username,
prisonCode = prisonCode,
officialVisitId = it.officialVisitId,
contactId = value.second!!,
officialVisitorId = value.first,
),
)
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,11 @@ import uk.gov.justice.digital.hmpps.officialvisitsapi.repository.OfficialVisitor
import uk.gov.justice.digital.hmpps.officialvisitsapi.repository.PrisonVisitSlotRepository
import uk.gov.justice.digital.hmpps.officialvisitsapi.service.auditing.AuditingService
import uk.gov.justice.digital.hmpps.officialvisitsapi.service.auditing.auditVisitChangeEvent
import uk.gov.justice.digital.hmpps.officialvisitsapi.service.events.outbound.Source
import uk.gov.justice.digital.hmpps.officialvisitsapi.service.metrics.MetricsEvents
import uk.gov.justice.digital.hmpps.officialvisitsapi.service.metrics.MetricsService
import uk.gov.justice.digital.hmpps.officialvisitsapi.service.metrics.VisitMetricInfo
import uk.gov.justice.digital.hmpps.officialvisitsapi.service.metrics.VisitorMetricInfo
import java.time.LocalDateTime

@Service
Expand All @@ -34,7 +36,7 @@ class OfficialVisitUpdateService(
private val officialVisitorRepository: OfficialVisitorRepository,
private val prisonVisitSlotRepository: PrisonVisitSlotRepository,
private val contactsService: ContactsService,
val metricsService: MetricsService,
private val metricsService: MetricsService,
private val auditingService: AuditingService,
) {
/**
Expand Down Expand Up @@ -210,6 +212,34 @@ class OfficialVisitUpdateService(
}
},
)
}.also {
it.visitorsAdded.forEach { value ->
metricsService.send(
MetricsEvents.ADD_VISITOR,
VisitorMetricInfo(
source = Source.DPS,
username = user.username,
prisonCode = prisonCode,
officialVisitId = officialVisitId,
contactId = value.contactId,
officialVisitorId = value.officialVisitorId,
),
)
}
}.also {
it.visitorsDeleted.forEach { value ->
metricsService.send(
MetricsEvents.REMOVE_VISITOR,
VisitorMetricInfo(
source = Source.DPS,
username = user.username,
prisonCode = prisonCode,
officialVisitId = officialVisitId,
contactId = value.contactId,
officialVisitorId = value.officialVisitorId,
),
)
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ import uk.gov.justice.digital.hmpps.officialvisitsapi.repository.PrisonTimeSlotR
import uk.gov.justice.digital.hmpps.officialvisitsapi.repository.PrisonVisitSlotRepository
import uk.gov.justice.digital.hmpps.officialvisitsapi.service.LocationsService
import uk.gov.justice.digital.hmpps.officialvisitsapi.service.User
import uk.gov.justice.digital.hmpps.officialvisitsapi.service.events.outbound.Source
import uk.gov.justice.digital.hmpps.officialvisitsapi.service.metrics.MetricsEvents
import uk.gov.justice.digital.hmpps.officialvisitsapi.service.metrics.MetricsService
import uk.gov.justice.digital.hmpps.officialvisitsapi.service.metrics.TimeSlotInfo
import java.time.LocalDate
import java.time.LocalDateTime

Expand All @@ -31,6 +35,7 @@ class PrisonTimeSlotService(
private val prisonerSearchClient: PrisonerSearchClient,
private val locationService: LocationsService,
private val officialVisitRepository: OfficialVisitRepository,
private val metricsService: MetricsService,
) {
@Transactional(readOnly = true)
fun getPrisonTimeSlotById(prisonTimeSlotId: Long): TimeSlot {
Expand All @@ -42,7 +47,17 @@ class PrisonTimeSlotService(
@Transactional
fun create(request: CreateTimeSlotRequest, user: User): TimeSlot {
request.validate()
return prisonTimeSlotRepository.saveAndFlush(request.toEntity(user.username)).toModel()
return prisonTimeSlotRepository.saveAndFlush(request.toEntity(user.username)).toModel().also {
metricsService.send(
eventType = MetricsEvents.TIMESLOT_ADDED,
info = TimeSlotInfo(
source = Source.DPS,
username = user.username,
prisonCode = request.prisonCode,
dayCode = request.dayCode.toString(),
),
)
}
}

@Transactional
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,24 @@ enum class MetricsEvents(val eventType: String) {
additionalInformation = additionalInformation,
)
},
ADD_VISITOR("OfficialVisitorAdded") {
override fun event(additionalInformation: MetricInfo) = OfficialVisitMetricTelemetry(
eventType = eventType,
additionalInformation = additionalInformation,
)
},
REMOVE_VISITOR("OfficialVisitorRemoved") {
override fun event(additionalInformation: MetricInfo) = OfficialVisitMetricTelemetry(
eventType = eventType,
additionalInformation = additionalInformation,
)
},
TIMESLOT_ADDED("TimeSlotAdded") {
override fun event(additionalInformation: MetricInfo) = OfficialVisitMetricTelemetry(
eventType = eventType,
additionalInformation = additionalInformation,
)
},
;

abstract fun event(
Expand All @@ -57,6 +75,7 @@ data class OfficialVisitMetricTelemetry(
val baseMap = mapOf(
"prison_code" to additionalInformation.prisonCode,
"source" to additionalInformation.source.toString(),
"username" to additionalInformation.username,
)
return when (additionalInformation) {
is VisitMetricInfo -> {
Expand All @@ -65,6 +84,14 @@ data class OfficialVisitMetricTelemetry(
is SearchInfo -> {
baseMap + additionalInformation.searchAdditionalInfo()
}

is VisitorMetricInfo -> {
baseMap + additionalInformation.visitorAdditionalInfo()
}

is TimeSlotInfo -> {
baseMap + additionalInformation.timeSLotInfo()
}
}
}

Expand All @@ -77,6 +104,9 @@ data class OfficialVisitMetricTelemetry(
"number_of_results" to additionalInformation.numberOfResults.toDouble(),
)
}
else -> {
emptyMap<String, Double>()
}
}

fun VisitMetricInfo.hoursBeforeStartTimeMetric(): Pair<String, Double> = "hoursBeforeStartTime" to ChronoUnit.HOURS.between(
Expand All @@ -91,9 +121,17 @@ data class OfficialVisitMetricTelemetry(

private fun VisitMetricInfo.visitAdditionalInfo(): Map<String, String> = mapOf(
"prisoner_number" to prisonerNumber,
"username" to username,
)

private fun VisitorMetricInfo.visitorAdditionalInfo(): Map<String, String> = mapOf(
"official_visit_id" to "$officialVisitId",
"official_visitor_id" to "$officialVisitorId",
"contact_id" to "$contactId",
)

private fun TimeSlotInfo.timeSLotInfo(): Map<String, String> = mapOf(
"day_code" to dayCode,
)
private fun OfficialVisitMetricTelemetry.visitMetrics(
additionalInformation: VisitMetricInfo,
): Map<String, Double> = listOfNotNull(
Expand Down Expand Up @@ -141,3 +179,19 @@ data class SearchInfo(
val visitStatuses: List<VisitStatusType>?,
val numberOfResults: Int = 0,
) : MetricInfo(username = username, prisonCode = prisonCode)

data class VisitorMetricInfo(
override val source: Source = Source.DPS,
override val username: String,
override val prisonCode: String,
val officialVisitId: Long,
val contactId: Long,
val officialVisitorId: Long,
) : MetricInfo(source = source, username = username, prisonCode = prisonCode)

data class TimeSlotInfo(
override val source: Source = Source.DPS,
override val username: String,
override val prisonCode: String,
val dayCode: String,
) : MetricInfo(source = source, username = username, prisonCode = prisonCode)
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ import uk.gov.justice.digital.hmpps.officialvisitsapi.service.ContactsService
import uk.gov.justice.digital.hmpps.officialvisitsapi.service.UserService
import uk.gov.justice.digital.hmpps.officialvisitsapi.service.auditing.AuditingService
import uk.gov.justice.digital.hmpps.officialvisitsapi.service.auditing.auditVisitCreateEvent
import uk.gov.justice.digital.hmpps.officialvisitsapi.service.events.outbound.Source
import uk.gov.justice.digital.hmpps.officialvisitsapi.service.metrics.MetricsEvents
import uk.gov.justice.digital.hmpps.officialvisitsapi.service.metrics.MetricsService
import uk.gov.justice.digital.hmpps.officialvisitsapi.service.metrics.VisitorMetricInfo
import java.time.LocalDateTime
import kotlin.jvm.optionals.getOrNull

Expand All @@ -29,6 +33,7 @@ class SyncOfficialVisitorService(
private val officialVisitorRepository: OfficialVisitorRepository,
private val contactsService: ContactsService,
private val visitorEquipmentRepository: VisitorEquipmentRepository,
private val metricsService: MetricsService,
private val auditingService: AuditingService,
) {
companion object {
Expand Down Expand Up @@ -74,7 +79,19 @@ class SyncOfficialVisitorService(
createdBy = request.createUsername ?: "SYNC",
createdTime = request.createDateTime ?: LocalDateTime.now(),
),
)
).also {
metricsService.send(
MetricsEvents.ADD_VISITOR,
info = VisitorMetricInfo(
source = Source.NOMIS,
username = it.createdBy,
prisonCode = visit.prisonCode,
officialVisitId = visit.officialVisitId,
contactId = it.contactId!!,
officialVisitorId = it.officialVisitorId,
),
)
}

return SyncAddVisitorResponse(
officialVisitId = visit.officialVisitId,
Expand Down Expand Up @@ -109,7 +126,19 @@ class SyncOfficialVisitorService(
visitorEquipmentRepository.deleteAllByOfficialVisitor(visitor)
}

visit.removeVisitor(visitor)
visit.removeVisitor(visitor).also {
metricsService.send(
MetricsEvents.REMOVE_VISITOR,
info = VisitorMetricInfo(
source = Source.NOMIS,
username = UserService.getClientAsUser("NOMIS").username,
prisonCode = visit.prisonCode,
officialVisitId = visit.officialVisitId,
contactId = visitor.contactId!!,
officialVisitorId = visitor.officialVisitorId,
),
)
}

return SyncRemoveVisitorResponse(
officialVisitId = visit.officialVisitId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,36 @@ import uk.gov.justice.digital.hmpps.officialvisitsapi.model.request.sync.SyncUpd
import uk.gov.justice.digital.hmpps.officialvisitsapi.model.response.sync.SyncTimeSlot
import uk.gov.justice.digital.hmpps.officialvisitsapi.repository.PrisonTimeSlotRepository
import uk.gov.justice.digital.hmpps.officialvisitsapi.repository.PrisonVisitSlotRepository
import uk.gov.justice.digital.hmpps.officialvisitsapi.service.events.outbound.Source
import uk.gov.justice.digital.hmpps.officialvisitsapi.service.metrics.MetricsEvents
import uk.gov.justice.digital.hmpps.officialvisitsapi.service.metrics.MetricsService
import uk.gov.justice.digital.hmpps.officialvisitsapi.service.metrics.TimeSlotInfo

@Service
@Transactional
class SyncTimeSlotService(val prisonTimeSlotRepository: PrisonTimeSlotRepository, val prisonVisitSlotRepository: PrisonVisitSlotRepository) {
class SyncTimeSlotService(
val prisonTimeSlotRepository: PrisonTimeSlotRepository,
val prisonVisitSlotRepository: PrisonVisitSlotRepository,
val metricsService: MetricsService,
) {
@Transactional(readOnly = true)
fun getPrisonTimeSlotById(prisonTimeSlotId: Long): SyncTimeSlot {
val prisonTimeSlotEntity = prisonTimeSlotRepository.findById(prisonTimeSlotId)
.orElseThrow { EntityNotFoundException("Prison time slot with ID $prisonTimeSlotId was not found") }
return prisonTimeSlotEntity.toSyncModel()
}

fun createPrisonTimeSlot(request: SyncCreateTimeSlotRequest) = prisonTimeSlotRepository.saveAndFlush(request.toEntity()).toSyncModel()
fun createPrisonTimeSlot(request: SyncCreateTimeSlotRequest) = prisonTimeSlotRepository.saveAndFlush(request.toEntity()).toSyncModel().also {
metricsService.send(
eventType = MetricsEvents.TIMESLOT_ADDED,
info = TimeSlotInfo(
source = Source.NOMIS,
username = request.createdBy,
prisonCode = request.prisonCode,
dayCode = request.dayCode.toString(),
),
)
}

fun updatePrisonTimeSlot(prisonTimeSlotId: Long, request: SyncUpdateTimeSlotRequest): SyncTimeSlot {
val timeSlotEntity = prisonTimeSlotRepository.findById(prisonTimeSlotId)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ package uk.gov.justice.digital.hmpps.officialvisitsapi.integration.resource
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.mockito.kotlin.eq
import org.mockito.kotlin.verify
import org.springframework.http.MediaType
import org.springframework.test.context.bean.override.mockito.MockitoBean
import org.springframework.test.web.reactive.server.WebTestClient
import org.springframework.test.web.reactive.server.expectBody
import org.springframework.transaction.annotation.Transactional
Expand Down Expand Up @@ -36,11 +39,17 @@ import uk.gov.justice.digital.hmpps.officialvisitsapi.service.events.outbound.Pe
import uk.gov.justice.digital.hmpps.officialvisitsapi.service.events.outbound.Source
import uk.gov.justice.digital.hmpps.officialvisitsapi.service.events.outbound.VisitInfo
import uk.gov.justice.digital.hmpps.officialvisitsapi.service.events.outbound.VisitorInfo
import uk.gov.justice.digital.hmpps.officialvisitsapi.service.metrics.MetricsEvents
import uk.gov.justice.digital.hmpps.officialvisitsapi.service.metrics.MetricsService
import uk.gov.justice.digital.hmpps.officialvisitsapi.service.metrics.VisitMetricInfo
import uk.gov.justice.digital.hmpps.officialvisitsapi.service.metrics.VisitorMetricInfo
import java.time.DayOfWeek
import java.time.LocalTime
import java.util.UUID

class CreateOfficialVisitIntegrationTest : IntegrationTestBase() {
@MockitoBean
private lateinit var metricsService: MetricsService

private val officialVisitor = OfficialVisitor(
visitorTypeCode = VisitorType.CONTACT,
Expand Down Expand Up @@ -110,6 +119,38 @@ class CreateOfficialVisitIntegrationTest : IntegrationTestBase() {
auditedEventRepository.findAll() hasSize 0

val officialVisitResponse = webTestClient.create(nextMondayAt9)
verify(metricsService).send(
eventType = eq(
MetricsEvents.CREATE,
),
info = eq(
VisitMetricInfo(
officialVisitId = officialVisitResponse.officialVisitId,
source = Source.DPS,
username = MOORLAND_PRISON_USER.username,
prisonCode = MOORLAND,
prisonerNumber = MOORLAND_PRISONER.number,
numberOfVisitors = nextMondayAt9.officialVisitors.size.toLong(),
locationType = null,
startTime = nextMondayAt9.startTime,
),
),
)
verify(metricsService).send(
eventType = eq(
MetricsEvents.ADD_VISITOR,
),
info = eq(
VisitorMetricInfo(
officialVisitId = officialVisitResponse.officialVisitId,
source = Source.DPS,
username = MOORLAND_PRISON_USER.username,
prisonCode = MOORLAND,
contactId = officialVisitResponse.visitorAndContactIds.first().second!!,
officialVisitorId = officialVisitResponse.visitorAndContactIds.first().first,
),
),
)

val persistedOfficialVisit = officialVisitRepository.findById(officialVisitResponse.officialVisitId).get()

Expand Down
Loading
Loading