Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: move v2 missions endpoints to REST #497

Merged
merged 1 commit into from
Jan 16, 2025
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

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,38 +1,115 @@
package fr.gouv.dgampa.rapportnav.infrastructure.api.bff.v2

import fr.gouv.dgampa.rapportnav.domain.use_cases.mission.CreateEnvMission
import fr.gouv.dgampa.rapportnav.domain.use_cases.mission.FakeMissionData
import fr.gouv.dgampa.rapportnav.domain.use_cases.mission.GetEnvMissions
import fr.gouv.dgampa.rapportnav.domain.use_cases.mission.GetMission
import fr.gouv.dgampa.rapportnav.domain.use_cases.mission.action.v2.GetEnvMissionById2
import fr.gouv.dgampa.rapportnav.domain.use_cases.user.GetControlUnitsForUser
import fr.gouv.dgampa.rapportnav.domain.use_cases.user.GetUserFromToken
import fr.gouv.dgampa.rapportnav.infrastructure.api.bff.model.Mission
import fr.gouv.dgampa.rapportnav.infrastructure.api.bff.model.v2.MissionEnv
import fr.gouv.dgampa.rapportnav.infrastructure.api.bff.model.v2.generalInfo.MissionGeneralInfo2
import io.swagger.v3.oas.annotations.Operation
import org.slf4j.LoggerFactory
import org.springframework.web.bind.annotation.*
import java.time.Instant
import kotlin.collections.plus

@RestController
@RequestMapping("/api/v2/missions")
class MissionRestController(
private val createEnvMission: CreateEnvMission,
private val getEnvMissionById2: GetEnvMissionById2,
private val getControlUnitsForUser: GetControlUnitsForUser,
private val getUserFromToken: GetUserFromToken,
private val getEnvMissions: GetEnvMissions,
private val getMission: GetMission,
private val fakeMissionData: FakeMissionData,
) {

private val logger = LoggerFactory.getLogger(MissionRestController::class.java)


/**
* Retrieves a list of missions from the environment and combines them with fictive missions specific to the user.
*
* This endpoint accepts query parameters `startDateTimeUtc` (required) and `endDateTimeUtc` (optional) to filter missions
* within a specific date range. It queries the environment for missions matching the user's control units and enriches
* the data to ensure completeness. Additionally, it appends fictive missions tailored for the user.
*
* @param startDateTimeUtc The start of the date range (UTC) for filtering missions.
* @param endDateTimeUtc The end of the date range (UTC) for filtering missions. Optional.
* @return A response containing a list of enriched missions, both retrieved and fictive, or an error status if the process fails.
*/
@GetMapping("")
@Operation(summary = "Get the list of actions on a mission Id")
fun getMissions(
@RequestParam startDateTimeUtc: Instant,
@RequestParam(required = false) endDateTimeUtc: Instant? = null
): List<Mission?> {
try {
// query MonitorEnv with the following filters
val envMissions = getEnvMissions.execute(
startedAfterDateTime = startDateTimeUtc,
startedBeforeDateTime = endDateTimeUtc,
pageNumber = null,
pageSize = null,
controlUnits = getControlUnitsForUser.execute()
)

// reconstruct the Missions with full data in order to have the right status/completeness
val fullMissions = envMissions?.map { getMission.execute(it.id, it) }

// transform the data for the API
val missions = fullMissions?.mapNotNull { it?.let { Mission.fromMissionEntity(it) } } ?: emptyList()


// temporarily add fictive missions
val user = getUserFromToken.execute()
val fakeMissions = fakeMissionData.getFakeMissionsforUser(user).map { Mission.fromMissionEntity(it) }
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We really need to find a way to remove fake missions, really


return missions + fakeMissions
} catch (e: Exception) {
logger.error("MissionRestController - failed to load missions from MonitorEnv", e)
throw Exception(e)
}
}

/**
* Retrieves a specific mission by its ID.
*
* This endpoint fetches a mission identified by the provided `missionId` path variable. If the mission exists, it
* returns the mission data transformed into the API response format. If the mission does not exist or an error occurs,
* it returns null.
*
* @param missionId The unique identifier of the mission to retrieve.
* @return The mission data as a `MissionEnv` object, or null if not found or an error occurs.
*/
@GetMapping("{missionId}")
fun getMissionById(
@PathVariable(name = "missionId") missionId: Int
): MissionEnv? {
try {
try {
val mission = getEnvMissionById2.execute(missionId) ?: return null
return MissionEnv.fromMissionEntity(mission)
}
catch (e: Exception) {
} catch (e: Exception) {
logger.error("Error while creating MonitorEnv mission : ", e)
return null
}
}


/**
* Creates a new mission in the MonitorEnv system.
*
* This endpoint accepts a request body containing the general information about the mission to be created. It uses
* the user's control units to associate the mission with the appropriate entities. Upon successful creation, it returns
* the newly created mission in the API response format.
*
* @param body The general information required to create a new mission.
* @return The created mission as a `MissionEnv` object, or null if an error occurs during creation.
*/
@PostMapping("")
@Operation(summary = "Create a new MonitorEnv mission")
fun createMission(
Expand All @@ -42,10 +119,9 @@ class MissionRestController(
val mission = createEnvMission.execute(
missionGeneralInfo = body,
controlUnitIds = getControlUnitsForUser.execute()
)?: return null
) ?: return null
return MissionEnv.fromMissionEnvEntity(mission)
}
catch (e: Exception) {
} catch (e: Exception) {
logger.error("Error while creating MonitorEnv mission : ", e)
return null
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import fr.gouv.dgampa.rapportnav.domain.entities.user.RoleTypeEnum
import fr.gouv.dgampa.rapportnav.domain.entities.user.User
import fr.gouv.dgampa.rapportnav.domain.repositories.user.IUserRepository
import fr.gouv.dgampa.rapportnav.domain.use_cases.auth.TokenService
import fr.gouv.gmampa.rapportnav.mocks.user.UserMock
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
Expand All @@ -27,17 +28,11 @@ class TokenServiceTests {
private lateinit var userRepository: IUserRepository


private val user: User = User(
private val user: User = UserMock.create(
id = 3,
firstName = "Jean",
lastName = "Dupont",
email = "jean.dupont@mer.gouv.fr",
password = "MyBeautifulPassword",
serviceId = 6,
roles = listOf(RoleTypeEnum.USER_ULAM)
)


@Test
fun `execute should have roles with claim user id and user role`() {
val tokenService = TokenService(jwtDecoder, jwtEncoder, userRepository)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
package fr.gouv.gmampa.rapportnav.infrastructure.bff.controllers

import fr.gouv.dgampa.rapportnav.RapportNavApplication
import fr.gouv.dgampa.rapportnav.domain.use_cases.mission.CreateEnvMission
import fr.gouv.dgampa.rapportnav.domain.use_cases.mission.FakeMissionData
import fr.gouv.dgampa.rapportnav.domain.use_cases.mission.GetEnvMissions
import fr.gouv.dgampa.rapportnav.domain.use_cases.mission.GetMission
import fr.gouv.dgampa.rapportnav.domain.use_cases.mission.action.v2.GetEnvMissionById2
import fr.gouv.dgampa.rapportnav.domain.use_cases.user.GetControlUnitsForUser
import fr.gouv.dgampa.rapportnav.domain.use_cases.user.GetUserFromToken
import fr.gouv.dgampa.rapportnav.infrastructure.api.bff.v2.MissionRestController
import fr.gouv.gmampa.rapportnav.mocks.mission.EnvMissionMock
import fr.gouv.gmampa.rapportnav.mocks.mission.EnvMissionMockv2
import fr.gouv.gmampa.rapportnav.mocks.mission.LegacyControlUnitEntityMock
import fr.gouv.gmampa.rapportnav.mocks.mission.MissionEntityMock
import fr.gouv.gmampa.rapportnav.mocks.mission.MissionGeneralInfo2Mock
import fr.gouv.gmampa.rapportnav.mocks.user.UserMock
import org.junit.jupiter.api.Test
import org.mockito.ArgumentMatchers.any
import org.mockito.Mockito.`when`
import org.mockito.kotlin.anyOrNull
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest
import org.springframework.http.MediaType
import org.springframework.test.context.ContextConfiguration
import org.springframework.test.context.bean.override.mockito.MockitoBean
import org.springframework.test.web.servlet.MockMvc
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post
import fr.gouv.dgampa.rapportnav.infrastructure.utils.GsonSerializer
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.content
import java.time.Instant

@AutoConfigureMockMvc(addFilters = false)
@ContextConfiguration(classes = [RapportNavApplication::class])
@WebMvcTest(MissionRestController::class)
class MissionRestControllerTest {

@Autowired
private lateinit var mockMvc: MockMvc

@MockitoBean
private lateinit var getEnvMissions: GetEnvMissions

@MockitoBean
private lateinit var getControlUnitsForUser: GetControlUnitsForUser

@MockitoBean
private lateinit var getMission: GetMission

@MockitoBean
private lateinit var getUserFromToken: GetUserFromToken

@MockitoBean
private lateinit var fakeMissionData: FakeMissionData

@MockitoBean
private lateinit var createEnvMission: CreateEnvMission

@MockitoBean
private lateinit var getEnvMissionById2: GetEnvMissionById2

@Test
fun `should return a list of missions`() {
// Arrange
val mockEnvMissions = listOf(
EnvMissionMock.create(id = 1),
EnvMissionMock.create(id = 2),
)
val mockMissionEntity = MissionEntityMock.create(id = 1)


val mockUser = UserMock.create()

`when`(getControlUnitsForUser.execute()).thenReturn(listOf(1))
`when`(getEnvMissions.execute(any(), any(), anyOrNull(), anyOrNull(), any())).thenReturn(mockEnvMissions)
`when`(getMission.execute(any(), any())).thenReturn(mockMissionEntity)
`when`(getUserFromToken.execute()).thenReturn(mockUser)
`when`(fakeMissionData.getFakeMissionsforUser(mockUser)).thenReturn(emptyList())

// Act & Assert
mockMvc.perform(
get("/api/v2/missions")
.param("startDateTimeUtc", Instant.now().toString())
)
.andExpect(status().isOk)
.andExpect(jsonPath("$.length()").value(mockEnvMissions.size))
}

@Test
fun `should return a mission by id`() {
// Arrange
val missionId = 1
val mockMission = EnvMissionMock.create(id = missionId)
`when`(getEnvMissionById2.execute(missionId)).thenReturn(mockMission)

// Act & Assert
mockMvc.perform(get("/api/v2/missions/{missionId}", missionId))
.andExpect(status().isOk)
.andExpect(jsonPath("$.id").value(missionId))
}

@Test
fun `should create a new mission`() {
val gson = GsonSerializer().create()
// Arrange
val requestBody = MissionGeneralInfo2Mock.create()
val controlUnitsIds = listOf(456)
val mockMission = EnvMissionMockv2.create(
id = 123,
controlUnits = listOf(LegacyControlUnitEntityMock.create(id = controlUnitsIds.first()))
)
`when`(getControlUnitsForUser.execute()).thenReturn(controlUnitsIds)
`when`(createEnvMission.execute(requestBody, controlUnitsIds)).thenReturn(mockMission)

// Act & Assert
mockMvc.perform(
post("/api/v2/missions")
.contentType(MediaType.APPLICATION_JSON)
.characterEncoding("UTF-8")
.content(gson.toJson(requestBody))
)
.andExpect(status().isOk)
.andExpect(jsonPath("$.id").value(123))
}

@Test
fun `should return null when mission creation fails`() {
val gson = GsonSerializer().create()

// Arrange
val requestBody = MissionGeneralInfo2Mock.create()
val controlUnitsIds = listOf(456)
`when`(getControlUnitsForUser.execute()).thenReturn(controlUnitsIds)
// Simulate mission creation returning null
`when`(
createEnvMission.execute(
requestBody,
controlUnitsIds
)
).thenThrow(RuntimeException("Mission creation failed"))
// Act & Assert
mockMvc.perform(
post("/api/v2/missions")
.contentType(MediaType.APPLICATION_JSON)
.characterEncoding("UTF-8")
.content(gson.toJson(requestBody))
)
.andExpect(status().isOk) // The status should be 200 OK
.andExpect(
content().string("")
)
}


}
Loading
Loading