Skip to content

Commit

Permalink
[Moyens et unités] Ajout de la dialog d'impossibilité de suppression …
Browse files Browse the repository at this point in the history
…de moyens liés à des missions (#932)

## Related Pull Requests & Issues

- Resolve #925
- Resolve #930

----

- [x] Tests E2E (Cypress)

---

- ~~Je n'ai pas encore ajouté le test e2e (pour la dialog
d'impossibilité de suppression).~~ (Done)
- La très large majeure partie du code de cette PR sont des ajouts de
tests unitaires. Les fixs sont assez petits et mes commits sont bien
séparés.
- Ce que je compte faire mais n'ai pas le temps de faire sur cette PR :
- Refactorer les `deleteControlUnitContact` &
`deleteControlUnitResource` use cases pour gérer les dialogs directement
dans les composants concernés sans Redux. Je l'ai déjà fait pour le
BackOffice dans une PR précédente.
- Ajouter des `try {} catch {}` avec une gestion des erreurs d'archivage
/ suppression à posteriori (ex: au moment où on demande à supprimer un
unité, elle n'est liée à aucune mission, mais au moment où on confirme,
elle l'est et ne peut donc plus être supprimée).
  • Loading branch information
ivangabriele authored Oct 31, 2023
2 parents 49d6150 + f91e51d commit 4d2f308
Show file tree
Hide file tree
Showing 56 changed files with 1,488 additions and 67 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,7 @@ interface IMissionRepository {

fun findByControlUnitId(controlUnitId: Int): List<MissionEntity>

fun findByControlUnitResourceId(controlUnitResourceId: Int): List<MissionEntity>

fun save(mission: MissionEntity): MissionDTO
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package fr.gouv.cacem.monitorenv.domain.use_cases.controlUnit

import fr.gouv.cacem.monitorenv.config.UseCase
import fr.gouv.cacem.monitorenv.domain.repositories.IMissionRepository

@UseCase
class CanDeleteControlUnitResource(
private val missionRepository: IMissionRepository,
) {
fun execute(controlUnitResourceId: Int): Boolean {
val missions = missionRepository.findByControlUnitResourceId(controlUnitResourceId)

return missions.isEmpty()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,20 @@ package fr.gouv.cacem.monitorenv.domain.use_cases.controlUnit

import fr.gouv.cacem.monitorenv.config.UseCase
import fr.gouv.cacem.monitorenv.domain.repositories.IControlUnitResourceRepository
import fr.gouv.cacem.monitorenv.infrastructure.database.repositories.exceptions.ForeignKeyConstraintException

@UseCase
class DeleteControlUnitResource(private val controlUnitResourceRepository: IControlUnitResourceRepository) {
class DeleteControlUnitResource(
private val canDeleteControlUnitResource: CanDeleteControlUnitResource,
private val controlUnitResourceRepository: IControlUnitResourceRepository,
) {
fun execute(controlUnitResourceId: Int) {
if (!canDeleteControlUnitResource.execute(controlUnitResourceId)) {
throw ForeignKeyConstraintException(
"Cannot delete control unit resource (ID=$controlUnitResourceId) due to existing relationships.",
)
}

return controlUnitResourceRepository.deleteById(controlUnitResourceId)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package fr.gouv.cacem.monitorenv.infrastructure.api.endpoints.publicapi

import fr.gouv.cacem.monitorenv.domain.use_cases.controlUnit.*
import fr.gouv.cacem.monitorenv.infrastructure.api.adapters.publicapi.inputs.CreateOrUpdateControlUnitResourceDataInput
import fr.gouv.cacem.monitorenv.infrastructure.api.adapters.publicapi.outputs.BooleanDataOutput
import fr.gouv.cacem.monitorenv.infrastructure.api.adapters.publicapi.outputs.ControlUnitResourceDataOutput
import fr.gouv.cacem.monitorenv.infrastructure.api.adapters.publicapi.outputs.FullControlUnitResourceDataOutput
import io.swagger.v3.oas.annotations.Operation
Expand All @@ -15,6 +16,7 @@ import org.springframework.web.bind.annotation.*
@Tag(name = "Control Unit Resources")
class ApiControlUnitResourcesController(
private val archiveControlUnitResource: ArchiveControlUnitResource,
private val canDeleteControlUnitResource: CanDeleteControlUnitResource,
private val createOrUpdateControlUnitResource: CreateOrUpdateControlUnitResource,
private val deleteControlUnitResource: DeleteControlUnitResource,
private val getControlUnitResources: GetControlUnitResources,
Expand All @@ -30,6 +32,16 @@ class ApiControlUnitResourcesController(
archiveControlUnitResource.execute(controlUnitResourceId)
}

@GetMapping("/{controlUnitResourceId}/can_delete")
@Operation(summary = "Can this control unit resource be deleted?")
fun canDelete(
@PathParam("Control unit resource ID")
@PathVariable(name = "controlUnitResourceId")
controlUnitResourceId: Int,
): BooleanDataOutput {
return canDeleteControlUnitResource.execute(controlUnitResourceId).let { BooleanDataOutput.get(it) }
}

@PostMapping("", consumes = ["application/json"])
@Operation(summary = "Create a control unit resource")
@ResponseStatus(HttpStatus.CREATED)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@ class JpaMissionRepository(
}
}

override fun findByControlUnitResourceId(controlUnitResourceId: Int): List<MissionEntity> {
return dbMissionRepository.findByControlUnitResourceId(controlUnitResourceId).map {
it.toMissionEntity(mapper)
}
}

override fun findAll(
startedAfter: Instant,
startedBefore: Instant?,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,4 +95,9 @@ interface IDBMissionRepository : JpaRepository<MissionModel, Int> {

@Query("SELECT mm FROM MissionModel mm JOIN mm.controlUnits mmcu WHERE mmcu.unit.id = :controlUnitId")
fun findByControlUnitId(controlUnitId: Int): List<MissionModel>

@Query(
"SELECT mm FROM MissionModel mm JOIN mm.controlResources mmcr WHERE mmcr.resource.id = :controlUnitResourceId",
)
fun findByControlUnitResourceId(controlUnitResourceId: Int): List<MissionModel>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package fr.gouv.cacem.monitorenv.domain.use_cases.administration

import com.nhaarman.mockitokotlin2.given
import com.nhaarman.mockitokotlin2.verify
import com.nhaarman.mockitokotlin2.verifyNoMoreInteractions
import fr.gouv.cacem.monitorenv.domain.repositories.IAdministrationRepository
import fr.gouv.cacem.monitorenv.infrastructure.database.repositories.exceptions.UnarchivedChildException
import org.assertj.core.api.Assertions.assertThatThrownBy
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.springframework.boot.test.mock.mockito.MockBean
import org.springframework.test.context.junit.jupiter.SpringExtension

@ExtendWith(SpringExtension::class)
class ArchiveAdministrationUTests {
@MockBean
private lateinit var administrationRepository: IAdministrationRepository

@MockBean
private lateinit var canArchiveAdministration: CanArchiveAdministration

@Test
fun `execute should archive when canArchive returns true`() {
val administrationId = 1

given(canArchiveAdministration.execute(administrationId)).willReturn(true)

ArchiveAdministration(administrationRepository, canArchiveAdministration).execute(administrationId)

verify(administrationRepository).archiveById(administrationId)
}

@Test
fun `execute should throw UnarchivedChildException when canArchive() returns false`() {
val administrationId = 1

given(canArchiveAdministration.execute(administrationId)).willReturn(false)

assertThatThrownBy {
ArchiveAdministration(administrationRepository, canArchiveAdministration).execute(administrationId)
}
.isInstanceOf(UnarchivedChildException::class.java)

verifyNoMoreInteractions(administrationRepository)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package fr.gouv.cacem.monitorenv.domain.use_cases.administration

import com.nhaarman.mockitokotlin2.given
import fr.gouv.cacem.monitorenv.domain.entities.administration.AdministrationEntity
import fr.gouv.cacem.monitorenv.domain.entities.controlUnit.ControlUnitEntity
import fr.gouv.cacem.monitorenv.domain.repositories.IAdministrationRepository
import fr.gouv.cacem.monitorenv.domain.use_cases.administration.dtos.FullAdministrationDTO
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.springframework.boot.test.mock.mockito.MockBean
import org.springframework.test.context.junit.jupiter.SpringExtension

@ExtendWith(SpringExtension::class)
class CanArchiveAdministrationUTests {
@MockBean
private lateinit var administrationRepository: IAdministrationRepository

@Test
fun `execute should return true when all control units are archived`() {
val administrationId = 1
val fullAdministration = FullAdministrationDTO(
administration = AdministrationEntity(
id = 1,
name = "Administration Name",
isArchived = false,
),
controlUnits = listOf(
ControlUnitEntity(
id = 0,
administrationId = 1,
areaNote = null,
departmentAreaInseeCode = null,
isArchived = true,
name = "Control Unit Name",
termsNote = null,
),
),
)

given(administrationRepository.findById(administrationId)).willReturn(fullAdministration)

val result = CanArchiveAdministration(administrationRepository).execute(administrationId)

assertThat(result).isTrue
}

@Test
fun `execute should return false when some control units are not archived`() {
val administrationId = 1
val fullAdministration = FullAdministrationDTO(
administration = AdministrationEntity(
id = 1,
name = "Administration Name",
isArchived = false,
),
controlUnits = listOf(
ControlUnitEntity(
id = 0,
administrationId = 1,
areaNote = null,
departmentAreaInseeCode = null,
isArchived = false,
name = "Control Unit Name",
termsNote = null,
),
),
)

given(administrationRepository.findById(administrationId)).willReturn(fullAdministration)

val result = CanArchiveAdministration(administrationRepository).execute(administrationId)

assertThat(result).isFalse
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package fr.gouv.cacem.monitorenv.domain.use_cases.administration

import com.nhaarman.mockitokotlin2.given
import fr.gouv.cacem.monitorenv.domain.entities.administration.AdministrationEntity
import fr.gouv.cacem.monitorenv.domain.entities.controlUnit.ControlUnitEntity
import fr.gouv.cacem.monitorenv.domain.repositories.IAdministrationRepository
import fr.gouv.cacem.monitorenv.domain.use_cases.administration.dtos.FullAdministrationDTO
import org.assertj.core.api.Assertions.assertThat
import org.junit.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.springframework.boot.test.mock.mockito.MockBean
import org.springframework.test.context.junit.jupiter.SpringExtension

@ExtendWith(SpringExtension::class)
class CanDeleteAdministrationUTests {
@MockBean
private lateinit var administrationRepository: IAdministrationRepository

@Test
fun `execute should return true when control units are empty`() {
val administrationId = 1
val fullAdministration = FullAdministrationDTO(
administration = AdministrationEntity(
id = 1,
name = "Administration Name",
isArchived = false,
),
controlUnits = listOf(),
)

given(administrationRepository.findById(administrationId)).willReturn(fullAdministration)

val result = CanDeleteAdministration(administrationRepository).execute(administrationId)

assertThat(result).isTrue
}

@Test
fun `execute should return false when control units are not empty`() {
val administrationId = 1
val fullAdministration = FullAdministrationDTO(
administration = AdministrationEntity(
id = 1,
name = "Administration Name",
isArchived = false,
),
controlUnits = listOf(
ControlUnitEntity(
id = 0,
administrationId = 1,
areaNote = null,
departmentAreaInseeCode = null,
isArchived = true,
name = "Control Unit Name",
termsNote = null,
),
),
)

given(administrationRepository.findById(administrationId)).willReturn(fullAdministration)

val result = CanDeleteAdministration(administrationRepository).execute(administrationId)

assertThat(result).isFalse
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
package fr.gouv.cacem.monitorenv.domain.use_cases
package fr.gouv.cacem.monitorenv.domain.use_cases.administration

import com.nhaarman.mockitokotlin2.given
import com.nhaarman.mockitokotlin2.times
import com.nhaarman.mockitokotlin2.verify
import fr.gouv.cacem.monitorenv.domain.entities.administration.AdministrationEntity
import fr.gouv.cacem.monitorenv.domain.repositories.IAdministrationRepository
import fr.gouv.cacem.monitorenv.domain.use_cases.administration.CreateOrUpdateAdministration
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
Expand All @@ -18,7 +17,7 @@ class CreateOrUpdateAdministrationUTests {
private lateinit var administrationRepository: IAdministrationRepository

@Test
fun `execute() should return save() result`() {
fun `execute should return save result`() {
val newAdministration = AdministrationEntity(
isArchived = false,
name = "Administration Name",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package fr.gouv.cacem.monitorenv.domain.use_cases.administration

import com.nhaarman.mockitokotlin2.given
import com.nhaarman.mockitokotlin2.verify
import fr.gouv.cacem.monitorenv.domain.repositories.IAdministrationRepository
import fr.gouv.cacem.monitorenv.infrastructure.database.repositories.exceptions.ForeignKeyConstraintException
import org.assertj.core.api.Assertions.assertThatThrownBy
import org.junit.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.springframework.boot.test.mock.mockito.MockBean
import org.springframework.test.context.junit.jupiter.SpringExtension

@ExtendWith(SpringExtension::class)
class DeleteAdministrationUTests {
@MockBean
private lateinit var administrationRepository: IAdministrationRepository

@MockBean
private lateinit var canDeleteAdministration: CanDeleteAdministration

@Test
fun `execute should delete when canDeleteAdministration returns true`() {
val administrationId = 1

given(canDeleteAdministration.execute(administrationId)).willReturn(true)

DeleteAdministration(administrationRepository, canDeleteAdministration).execute(administrationId)

verify(administrationRepository).deleteById(administrationId)
}

@Test
fun `execute should throw ForeignKeyConstraintException when canDeleteAdministration returns false`() {
val administrationId = 1

given(canDeleteAdministration.execute(administrationId)).willReturn(false)

assertThatThrownBy {
DeleteAdministration(administrationRepository, canDeleteAdministration).execute(administrationId)
}
.isInstanceOf(ForeignKeyConstraintException::class.java)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package fr.gouv.cacem.monitorenv.domain.use_cases.administration

import com.nhaarman.mockitokotlin2.given
import fr.gouv.cacem.monitorenv.domain.entities.administration.AdministrationEntity
import fr.gouv.cacem.monitorenv.domain.repositories.IAdministrationRepository
import fr.gouv.cacem.monitorenv.domain.use_cases.administration.dtos.FullAdministrationDTO
import org.assertj.core.api.Assertions.assertThat
import org.junit.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.springframework.boot.test.mock.mockito.MockBean
import org.springframework.test.context.junit.jupiter.SpringExtension

@ExtendWith(SpringExtension::class)
class GetAdministrationByIdUTests {
@MockBean
private lateinit var administrationRepository: IAdministrationRepository

@Test
fun `execute should return an administration by its ID`() {
val administrationId = 1
val fullAdministration = FullAdministrationDTO(
administration = AdministrationEntity(
id = 1,
name = "Administration Name",
isArchived = false,
),
controlUnits = listOf(),
)

given(administrationRepository.findById(administrationId)).willReturn(fullAdministration)

val result = GetAdministrationById(administrationRepository).execute(administrationId)

assertThat(result).isEqualTo(fullAdministration)
}
}
Loading

0 comments on commit 4d2f308

Please sign in to comment.