Skip to content

Commit

Permalink
HAI-1331 Remove attachments when täydennyspyyntö is canceled (#891)
Browse files Browse the repository at this point in the history
When a täydennyspyyntö is cancelled in Allu, remove any täydennys
attachment contents from Blob storage.

Also, add missing audit logging for the removal of the täydennys and
täydennyspyyntö when they are deleted after the täydennyspyyntö is
cancelled in Allu.  Allu is marked as the actor. Even though technically
the data is deleted by Haitaton itself, Allu initiates the process by
cancelling the täydennyspyyntö.

Add hakemus ID to the täydennyspyyntö domain class so that it's logged
as well.
  • Loading branch information
corvidian authored Dec 5, 2024
1 parent abc3cff commit f65f432
Show file tree
Hide file tree
Showing 7 changed files with 124 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ class TaydennysServiceITest(
}

@Test
fun `returns null when Allu doesn't have the täydennyspyyntö`() {
fun `returns null when Allu doesn't have the taydennyspyynto`() {
val hakemus = hakemusFactory.builder().withStatus(alluId = alluId).save()
every { alluClient.getInformationRequest(hakemus.alluid!!) } returns null

Expand Down Expand Up @@ -368,6 +368,90 @@ class TaydennysServiceITest(
copy(id = fixedUUID, yhteyshenkilot = yhteyshenkilot.map { it.copy(id = fixedUUID) })
}

@Nested
inner class RemoveTaydennyspyyntoIfItExists {
@Test
fun `logs removing the taydennyspyynto and taydennys to audit logs`() {
val hakemus =
hakemusFactory
.builder()
.withStatus(ApplicationStatus.WAITING_INFORMATION, 42)
.saveEntity()
val taydennys = taydennysFactory.save(applicationId = hakemus.id)
val taydennyspyynto = taydennyspyyntoRepository.findByApplicationId(hakemus.id)!!
auditLogRepository.deleteAll()

taydennysService.removeTaydennyspyyntoIfItExists(hakemus)

val taydennysLogs = auditLogRepository.findByType(ObjectType.TAYDENNYS)
assertThat(taydennysLogs).single().isSuccess(Operation.DELETE) {
hasServiceActor("Allu")
withTarget {
hasNoObjectAfter()
hasObjectBefore<Taydennys> {
prop(Taydennys::id).isEqualTo(taydennys.id)
prop(Taydennys::hakemusId).isEqualTo(hakemus.id)
}
}
}
val taydennyspyyntoLogs = auditLogRepository.findByType(ObjectType.TAYDENNYSPYYNTO)
assertThat(taydennyspyyntoLogs).single().isSuccess(Operation.DELETE) {
hasServiceActor("Allu")
withTarget {
hasNoObjectAfter()
hasObjectBefore<Taydennyspyynto> {
prop(Taydennyspyynto::id).isEqualTo(taydennyspyynto.id)
prop(Taydennyspyynto::hakemusId).isEqualTo(taydennyspyynto.applicationId)
}
}
}
}

@Test
fun `removes and logs the taydennyspyynto when there is no taydennys`() {
val hakemus =
hakemusFactory
.builder()
.withStatus(ApplicationStatus.WAITING_INFORMATION, 42)
.saveEntity()
val taydennyspyynto = taydennyspyyntoFactory.save(hakemus.id)
auditLogRepository.deleteAll()

taydennysService.removeTaydennyspyyntoIfItExists(hakemus)

assertThat(taydennyspyyntoRepository.findAll()).isEmpty()
val taydennyspyyntoLogs = auditLogRepository.findAll()
assertThat(taydennyspyyntoLogs).single().isSuccess(Operation.DELETE) {
hasServiceActor("Allu")
withTarget {
hasTargetType(ObjectType.TAYDENNYSPYYNTO)
hasNoObjectAfter()
hasObjectBefore(taydennyspyynto)
}
}
}

@Test
fun `removes taydennys attachments from Blob storage when the new status is HANDLING`() {
val hakemus =
hakemusFactory
.builder()
.withStatus(ApplicationStatus.WAITING_INFORMATION, 42)
.saveEntity()
val taydennys = taydennysFactory.save(applicationId = hakemus.id)
attachmentFactory.save(taydennys = taydennys).withContent()
attachmentFactory.save(taydennys = taydennys).withContent()
assertThat(fileClient.listBlobs(Container.HAKEMUS_LIITTEET)).hasSize(2)

taydennysService.removeTaydennyspyyntoIfItExists(hakemus)

assertThat(fileClient.listBlobs(Container.HAKEMUS_LIITTEET)).isEmpty()
assertThat(attachmentRepository.findAll()).isEmpty()
assertThat(taydennysRepository.findAll()).isEmpty()
assertThat(taydennyspyyntoRepository.findAll()).isEmpty()
}
}

@Nested
inner class SendTaydennys {
@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,18 @@ class AuditLogService(private val auditLogRepository: AuditLogRepository) {
objectAfter = null,
)

fun <ID, T : HasId<ID>> deleteEntryForAllu(type: ObjectType, deletedObject: T) =
AuditLogEntry(
operation = Operation.DELETE,
status = Status.SUCCESS,
userId = ALLU_AUDIT_LOG_USERID,
userRole = UserRole.SERVICE,
objectId = deletedObject.id!!.toString(),
objectType = type,
objectBefore = deletedObject.toChangeLogJsonString(),
objectAfter = null,
)

fun <ID, T : HasId<ID>> createEntry(userId: String, type: ObjectType, createdObject: T) =
AuditLogEntry(
operation = Operation.CREATE,
Expand All @@ -95,7 +107,7 @@ class AuditLogService(private val auditLogRepository: AuditLogRepository) {
userId: String,
type: ObjectType,
objectBefore: T,
objectAfter: T
objectAfter: T,
): AuditLogEntry? {
val jsonBefore = objectBefore.toChangeLogJsonString()
val jsonAfter = objectAfter.toChangeLogJsonString()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,9 @@ abstract class ChangeLoggingService<ID, T : HasId<ID>>(
open fun logDelete(before: T, userId: String) {
auditLogService.create(AuditLogService.deleteEntry(userId, objectType, before))
}

@Transactional(propagation = Propagation.MANDATORY)
open fun logDeleteFromAllu(before: T) {
auditLogService.create(AuditLogService.deleteEntryForAllu(objectType, before))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -123,14 +123,30 @@ class TaydennysService(
return taydennys
}

/**
* Delete the täydennyspyyntö related to the given application if the application has one. The
* related objects (täydennys and it's attachments, customers and contacts) are removed as well.
*
* The deletions are logged to have been done by Allu, since this is called from the Allu event
* handler.
*/
@Transactional
fun removeTaydennyspyyntoIfItExists(application: HakemusEntity) {
logger.info {
"A hakemus has has entered handling. Checking if there's a täydennyspyyntö for the hakemus. ${application.logString()}"
}

taydennyspyyntoRepository.findByApplicationId(application.id)?.let {
taydennysRepository.findByApplicationId(application.id)?.also {
logger.info { "A täydennys was found. Removing it." }
attachmentService.deleteAllAttachments(it)
taydennysLoggingService.logDeleteFromAllu(it.toDomain())
taydennysRepository.delete(it)
taydennysRepository.flush()
}

taydennyspyyntoRepository.findByApplicationId(application.id)?.also {
logger.info { "A täydennyspyyntö was found. Removing it." }
taydennyspyyntoLoggingService.logDeleteFromAllu(it.toDomain())
taydennyspyyntoRepository.delete(it)
taydennyspyyntoRepository.flush()
sendInformationRequestCanceledEmails(application)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import java.util.UUID

data class Taydennyspyynto(
override val id: UUID,
val hakemusId: Long,
val kentat: Map<InformationRequestFieldKey, String>,
) : HasId<UUID> {
fun toResponse(): TaydennyspyyntoResponse =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,5 @@ class TaydennyspyyntoEntity(
@MapKeyEnumerated(EnumType.STRING)
val kentat: MutableMap<InformationRequestFieldKey, String> = mutableMapOf(),
) {
fun toDomain(): Taydennyspyynto = Taydennyspyynto(id, kentat.toMap())
fun toDomain(): Taydennyspyynto = Taydennyspyynto(id, applicationId, kentat.toMap())
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,9 @@ class TaydennyspyyntoFactory(private val taydennyspyyntoRepository: Taydennyspyy

fun create(
id: UUID = DEFAULT_ID,
hakemusId: Long = ApplicationFactory.DEFAULT_APPLICATION_ID,
kentat: Map<InformationRequestFieldKey, String> = DEFAULT_KENTAT,
): Taydennyspyynto = Taydennyspyynto(id = id, kentat = kentat)
): Taydennyspyynto = Taydennyspyynto(id = id, hakemusId = hakemusId, kentat = kentat)

fun TaydennyspyyntoEntity.addKentta(key: InformationRequestFieldKey, message: String) =
kentat.put(key, message)
Expand Down

0 comments on commit f65f432

Please sign in to comment.