refactor(pcp-request-service): rename REST endpoints and DTOs for clarity

- GET /v1/requests/with-geometry → /v1/requests/map
- GET /v1/requests/{id}/with-cells → /v1/requests/{id}/cells
- GET /v1/cells/with-requests → /v1/cells/priority-map
- CreateRequestRequestDto → CreateRequestDto
- ListRequestsQueryDto → RequestListFilter
- RequestWithGeometry* → RequestMap* (RequestMapItemDto, RequestMapPageDto)
- CellsWithRequestsResponseDto → CellPriorityMapResponseDto
- DeleteRequestStatusDto removed; status field removed from DeleteRequestResponseDto

Updated all consumers (pcp-complex-mission-service, pcp-ui-service, slots-service),
tests, and OpenAPI YAML.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Дмитрий Соловьев
2026-05-30 23:28:45 +03:00
parent 3d508b6be9
commit bb84844674
21 changed files with 545 additions and 136 deletions
@@ -133,8 +133,8 @@ class CellsControllerTest {
}
@Test
fun `get v1 cells with requests returns request fragments`() {
mockMvc.perform(get("/v1/cells/with-requests").accept(MediaType.APPLICATION_JSON))
fun `get v1 cells priority map returns request fragments`() {
mockMvc.perform(get("/v1/cells/priority-map").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk)
.andExpect(jsonPath("$.items").isArray)
.andExpect(jsonPath("$.items[0].cellNum").value(42))
@@ -150,9 +150,9 @@ class CellsControllerTest {
}
@Test
fun `get v1 cells with requests rejects partial aggregation parameters`() {
fun `get v1 cells priority map rejects partial aggregation parameters`() {
mockMvc.perform(
get("/v1/cells/with-requests")
get("/v1/cells/priority-map")
.queryParam("countLat", "2")
.accept(MediaType.APPLICATION_JSON),
)
@@ -162,9 +162,9 @@ class CellsControllerTest {
}
@Test
fun `get v1 cells with requests rejects invalid numeric parameters`() {
fun `get v1 cells priority map rejects invalid numeric parameters`() {
mockMvc.perform(
get("/v1/cells/with-requests")
get("/v1/cells/priority-map")
.queryParam("minImportance", "-1")
.accept(MediaType.APPLICATION_JSON),
)
@@ -173,7 +173,7 @@ class CellsControllerTest {
.andExpect(jsonPath("$.message").value("minImportance must be greater than or equal to 0"))
mockMvc.perform(
get("/v1/cells/with-requests")
get("/v1/cells/priority-map")
.queryParam("countLat", "0")
.queryParam("countLong", "1")
.accept(MediaType.APPLICATION_JSON),
@@ -184,9 +184,9 @@ class CellsControllerTest {
}
@Test
fun `get v1 cells with requests accepts complete aggregation parameters`() {
fun `get v1 cells priority map accepts complete aggregation parameters`() {
mockMvc.perform(
get("/v1/cells/with-requests")
get("/v1/cells/priority-map")
.queryParam("countLat", "1")
.queryParam("countLong", "1")
.accept(MediaType.APPLICATION_JSON),
@@ -11,6 +11,7 @@ import org.mockito.ArgumentMatchers.isNull
import org.mockito.Mockito.doAnswer
import org.mockito.Mockito.doReturn
import org.mockito.Mockito.mock
import org.nstart.dep265.requestservice.dto.CreateRequestDto
import org.nstart.dep265.requestservice.entity.EarthCellEntity
import org.nstart.dep265.requestservice.entity.RequestEntity
import org.nstart.dep265.requestservice.entity.RequestCellEntity
@@ -345,6 +346,32 @@ class RequestControllerOpenApiSkeletonTest {
.andExpect(jsonPath("$.items[0].importance").value(10.0))
}
@Test
fun `get v1 requests map returns map items with geometry`() {
doReturn(PageImpl(listOf(existingRequest())))
.`when`(requestRepository)
.findRequests(
anyBoolean(),
deletedStatusMatcher(),
isNull(),
isNull(),
isNull(),
isNull(),
isNull(),
isNull(),
isNull(),
isNull(),
pageableMatcher(),
)
mockMvc.perform(get("/v1/requests/map").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk)
.andExpect(jsonPath("$.items[0].name").value("Тест1"))
.andExpect(jsonPath("$.items[0].geometry").value("POLYGON ((37.5 55.5, 37.7 55.5, 37.7 55.7, 37.5 55.7, 37.5 55.5))"))
.andExpect(jsonPath("$.items[0].importance").value(10.0))
.andExpect(jsonPath("$.items[0].coveragePercent").value(50.0))
}
@Test
fun `get v1 requests rejects unsupported sort field`() {
mockMvc.perform(
@@ -370,7 +397,7 @@ class RequestControllerOpenApiSkeletonTest {
}
@Test
fun `get v1 request with cells returns request and cell projection fields`() {
fun `get v1 request cells returns request and cell projection fields`() {
val id = UUID.fromString("3fa85f64-5717-4562-b3fc-2c963f66afa6")
val earthCell = EarthCellEntity(
cellId = 1,
@@ -397,7 +424,7 @@ class RequestControllerOpenApiSkeletonTest {
.`when`(requestCellRepository)
.findWithCellByRequestId(id)
mockMvc.perform(get("/v1/requests/$id/with-cells").accept(MediaType.APPLICATION_JSON))
mockMvc.perform(get("/v1/requests/$id/cells").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk)
.andExpect(jsonPath("$.request.id").value(id.toString()))
.andExpect(jsonPath("$.request.name").value("Тест1"))
@@ -411,7 +438,7 @@ class RequestControllerOpenApiSkeletonTest {
}
@Test
fun `get v1 request with cells returns empty cells for request without projections`() {
fun `get v1 request cells returns empty cells for request without projections`() {
val id = UUID.fromString("3fa85f64-5717-4562-b3fc-2c963f66afa6")
doReturn(Optional.of(existingRequest()))
.`when`(requestRepository)
@@ -420,14 +447,14 @@ class RequestControllerOpenApiSkeletonTest {
.`when`(requestCellRepository)
.findWithCellByRequestId(id)
mockMvc.perform(get("/v1/requests/$id/with-cells").accept(MediaType.APPLICATION_JSON))
mockMvc.perform(get("/v1/requests/$id/cells").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk)
.andExpect(jsonPath("$.request.id").value(id.toString()))
.andExpect(jsonPath("$.cells").isEmpty)
}
@Test
fun `get v1 request with cells returns deleted request with empty cells`() {
fun `get v1 request cells returns deleted request with empty cells`() {
val id = UUID.fromString("3fa85f64-5717-4562-b3fc-2c963f66afa6")
val request = existingRequest().also { existingRequest ->
existingRequest.status = RequestStatus.DELETED
@@ -440,7 +467,7 @@ class RequestControllerOpenApiSkeletonTest {
.`when`(requestCellRepository)
.findWithCellByRequestId(id)
mockMvc.perform(get("/v1/requests/$id/with-cells").accept(MediaType.APPLICATION_JSON))
mockMvc.perform(get("/v1/requests/$id/cells").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk)
.andExpect(jsonPath("$.request.status").value("DELETED"))
.andExpect(jsonPath("$.request.deletedAt").exists())
@@ -454,7 +481,7 @@ class RequestControllerOpenApiSkeletonTest {
mockMvc.perform(get("/v1/requests/$id").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isNotFound)
mockMvc.perform(get("/v1/requests/$id/with-cells").accept(MediaType.APPLICATION_JSON))
mockMvc.perform(get("/v1/requests/$id/cells").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isNotFound)
mockMvc.perform(delete("/v1/requests/$id").accept(MediaType.APPLICATION_JSON))
@@ -18,7 +18,7 @@ class RequestApiDtoContractTest {
@Test
fun `create request dto matches openapi input fields`() {
val request = objectMapper.readValue<CreateRequestRequestDto>(
val request = objectMapper.readValue<CreateRequestDto>(
"""
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
@@ -66,14 +66,14 @@ class RequestApiDtoContractTest {
""".trimIndent()
assertFailsWith<Exception> {
objectMapper.readValue<CreateRequestRequestDto>(payloadWithSurveyType)
objectMapper.readValue<CreateRequestDto>(payloadWithSurveyType)
}
}
@Test
fun `create request serialization does not expose survey type`() {
val json = objectMapper.writeValueAsString(
CreateRequestRequestDto(
CreateRequestDto(
id = UUID.fromString("3fa85f64-5717-4562-b3fc-2c963f66afa6"),
name = "Тест1",
geometry = "POLYGON ((37.5 55.5, 37.7 55.5, 37.7 55.7, 37.5 55.7, 37.5 55.5))",
@@ -212,7 +212,7 @@ class CellsQueryServiceJpaTest @Autowired constructor(
)
entityManager.clear()
val response = service.listCellsWithRequests(
val response = service.listCellsPriorityMap(
minImportance = null,
countLat = null,
countLong = null,
@@ -234,7 +234,7 @@ class CellsQueryServiceJpaTest @Autowired constructor(
saveCell(cellNum = 11, importance = 2.0)
entityManager.clear()
val response = service.listCellsWithRequests(
val response = service.listCellsPriorityMap(
minImportance = 2.0,
countLat = null,
countLong = null,
@@ -249,7 +249,7 @@ class CellsQueryServiceJpaTest @Autowired constructor(
saveCell(cellNum = 11, importance = 1.0)
entityManager.clear()
val response = service.listCellsWithRequests(
val response = service.listCellsPriorityMap(
minImportance = 0.0,
countLat = null,
countLong = null,
@@ -264,7 +264,7 @@ class CellsQueryServiceJpaTest @Autowired constructor(
saveCell(cellNum = 11, importance = 0.002)
entityManager.clear()
val response = service.listCellsWithRequests(
val response = service.listCellsPriorityMap(
minImportance = 0.001,
countLat = null,
countLong = null,
@@ -121,7 +121,7 @@ class CellsQueryServiceTest {
}
val service = service(earthCellRepository)
val response = service.listCellsWithRequests(
val response = service.listCellsPriorityMap(
minImportance = null,
countLat = null,
countLong = null,
@@ -149,7 +149,7 @@ class CellsQueryServiceTest {
}
val service = service(earthCellRepository)
val response = service.listCellsWithRequests(
val response = service.listCellsPriorityMap(
minImportance = 2.0,
countLat = null,
countLong = null,
@@ -164,7 +164,7 @@ class CellsQueryServiceTest {
val service = service(emptyCellsRepository())
assertThrows<InvalidCellsQueryException> {
service.listCellsWithRequests(
service.listCellsPriorityMap(
minImportance = null,
countLat = 2,
countLong = null,
@@ -172,7 +172,7 @@ class CellsQueryServiceTest {
}
assertThrows<InvalidCellsQueryException> {
service.listCellsWithRequests(
service.listCellsPriorityMap(
minImportance = null,
countLat = null,
countLong = 2,
@@ -194,7 +194,7 @@ class CellsQueryServiceTest {
}
val service = service(earthCellRepository)
val response = service.listCellsWithRequests(
val response = service.listCellsPriorityMap(
minImportance = null,
countLat = 1,
countLong = 2,
@@ -2,7 +2,7 @@ package org.nstart.dep265.requestservice.service
import jakarta.persistence.EntityManager
import org.junit.jupiter.api.Test
import org.nstart.dep265.requestservice.dto.ListRequestsQueryDto
import org.nstart.dep265.requestservice.dto.RequestListFilter
import org.nstart.dep265.requestservice.dto.RequestStatusDto
import org.nstart.dep265.requestservice.dto.SurveyTypeDto
import org.nstart.dep265.requestservice.PcpRequestServiceApplication
@@ -57,7 +57,7 @@ class RequestServiceListRequestsJpaTest @Autowired constructor(
val activeId = saveRequest(status = RequestStatus.ACTIVE, createdAt = "2026-01-02T00:00:00")
saveRequest(status = RequestStatus.DELETED, createdAt = "2026-01-03T00:00:00")
val response = service.listRequests(ListRequestsQueryDto())
val response = service.listRequests(RequestListFilter())
assertEquals(listOf(activeId), response.items.map { request -> request.id })
assertEquals("Тест1", response.items.single().name)
@@ -65,12 +65,25 @@ class RequestServiceListRequestsJpaTest @Autowired constructor(
assertEquals(1, response.totalPages)
}
@Test
fun `list requests with geometry returns geometry and keeps list filters`() {
val activeId = saveRequest(status = RequestStatus.ACTIVE, createdAt = "2026-01-02T00:00:00")
saveRequest(status = RequestStatus.DELETED, createdAt = "2026-01-03T00:00:00")
val response = service.listRequestsForMap(RequestListFilter())
assertEquals(listOf(activeId), response.items.map { request -> request.id })
assertEquals("POLYGON ((37.5 55.5, 37.7 55.5, 37.7 55.7, 37.5 55.7, 37.5 55.5))", response.items.single().geometry)
assertEquals(1, response.totalItems)
assertEquals(1, response.totalPages)
}
@Test
fun `list requests includes deleted when includeDeleted is true`() {
val activeId = saveRequest(status = RequestStatus.ACTIVE, createdAt = "2026-01-02T00:00:00")
val deletedId = saveRequest(status = RequestStatus.DELETED, createdAt = "2026-01-03T00:00:00")
val response = service.listRequests(ListRequestsQueryDto(includeDeleted = true))
val response = service.listRequests(RequestListFilter(includeDeleted = true))
assertEquals(listOf(deletedId, activeId), response.items.map { request -> request.id })
assertEquals(2, response.totalItems)
@@ -81,7 +94,7 @@ class RequestServiceListRequestsJpaTest @Autowired constructor(
val activeId = saveRequest(status = RequestStatus.ACTIVE)
saveRequest(status = RequestStatus.ACCEPTED)
val response = service.listRequests(ListRequestsQueryDto(status = RequestStatusDto.ACTIVE))
val response = service.listRequests(RequestListFilter(status = RequestStatusDto.ACTIVE))
assertEquals(listOf(activeId), response.items.map { request -> request.id })
}
@@ -91,7 +104,7 @@ class RequestServiceListRequestsJpaTest @Autowired constructor(
val rsaId = saveRequest(surveyType = RequestSurveyType.RSA)
saveRequest(surveyType = RequestSurveyType.OPTICS)
val response = service.listRequests(ListRequestsQueryDto(surveyType = SurveyTypeDto.RSA))
val response = service.listRequests(RequestListFilter(surveyType = SurveyTypeDto.RSA))
assertEquals(listOf(rsaId), response.items.map { request -> request.id })
}
@@ -101,7 +114,7 @@ class RequestServiceListRequestsJpaTest @Autowired constructor(
val matchedId = saveRequest(kpp = mutableListOf(1, 2))
saveRequest(kpp = mutableListOf(3, 4))
val response = service.listRequests(ListRequestsQueryDto(kpp = 2))
val response = service.listRequests(RequestListFilter(kpp = 2))
assertEquals(listOf(matchedId), response.items.map { request -> request.id })
}
@@ -111,7 +124,7 @@ class RequestServiceListRequestsJpaTest @Autowired constructor(
val highPriorityId = saveRequest(highPriorityTransmit = true)
saveRequest(highPriorityTransmit = false)
val response = service.listRequests(ListRequestsQueryDto(highPriorityTransmit = true))
val response = service.listRequests(RequestListFilter(highPriorityTransmit = true))
assertEquals(listOf(highPriorityId), response.items.map { request -> request.id })
}
@@ -123,7 +136,7 @@ class RequestServiceListRequestsJpaTest @Autowired constructor(
saveRequest(beginDateTime = "2026-02-01T00:00:00", endDateTime = "2026-02-28T00:00:00")
val response = service.listRequests(
ListRequestsQueryDto(
RequestListFilter(
beginFrom = OffsetDateTime.parse("2026-01-10T00:00:00Z"),
beginTo = OffsetDateTime.parse("2026-01-31T23:59:59Z"),
)
@@ -139,7 +152,7 @@ class RequestServiceListRequestsJpaTest @Autowired constructor(
saveRequest(endDateTime = "2026-02-01T00:00:00")
val response = service.listRequests(
ListRequestsQueryDto(
RequestListFilter(
endFrom = OffsetDateTime.parse("2026-01-10T00:00:00Z"),
endTo = OffsetDateTime.parse("2026-01-31T23:59:59Z"),
)
@@ -154,7 +167,7 @@ class RequestServiceListRequestsJpaTest @Autowired constructor(
saveRequest(createdAt = "2026-01-02T00:00:00")
val oldestId = saveRequest(createdAt = "2026-01-01T00:00:00")
val response = service.listRequests(ListRequestsQueryDto(page = 1, size = 2))
val response = service.listRequests(RequestListFilter(page = 1, size = 2))
assertEquals(listOf(oldestId), response.items.map { request -> request.id })
assertEquals(1, response.page)
@@ -169,7 +182,7 @@ class RequestServiceListRequestsJpaTest @Autowired constructor(
val newestId = saveRequest(createdAt = "2026-01-03T00:00:00")
val middleId = saveRequest(createdAt = "2026-01-02T00:00:00")
val response = service.listRequests(ListRequestsQueryDto())
val response = service.listRequests(RequestListFilter())
assertEquals(listOf(newestId, middleId, oldestId), response.items.map { request -> request.id })
}
@@ -179,7 +192,7 @@ class RequestServiceListRequestsJpaTest @Autowired constructor(
val latestBeginId = saveRequest(beginDateTime = "2026-01-03T00:00:00")
val earliestBeginId = saveRequest(beginDateTime = "2026-01-01T00:00:00")
val response = service.listRequests(ListRequestsQueryDto(sort = "beginDateTime,asc"))
val response = service.listRequests(RequestListFilter(sort = "beginDateTime,asc"))
assertEquals(listOf(earliestBeginId, latestBeginId), response.items.map { request -> request.id })
}
@@ -11,8 +11,8 @@ import org.mockito.Mockito.mock
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyNoInteractions
import org.nstart.dep265.requestservice.dto.CreateRequestRequestDto
import org.nstart.dep265.requestservice.dto.ListRequestsQueryDto
import org.nstart.dep265.requestservice.dto.CreateRequestDto
import org.nstart.dep265.requestservice.dto.RequestListFilter
import org.nstart.dep265.requestservice.dto.OpticsParamsDto
import org.nstart.dep265.requestservice.dto.OpticsResultTypeDto
import org.nstart.dep265.requestservice.entity.EarthCellEntity
@@ -215,12 +215,38 @@ class RequestServiceTest {
pageableMatcher(),
)
val response = service.listRequests(ListRequestsQueryDto())
val response = service.listRequests(RequestListFilter())
assertEquals(REQUEST_NAME, response.items.single().name)
assertEquals(REQUEST_IMPORTANCE, response.items.single().importance)
}
@Test
fun `list requests with geometry returns expanded summary`() {
doReturn(PageImpl(listOf(existingRequest())))
.`when`(requestRepository)
.findRequests(
anyBoolean(),
deletedStatusMatcher(),
isNull(),
isNull(),
isNull(),
isNull(),
isNull(),
isNull(),
isNull(),
isNull(),
pageableMatcher(),
)
val response = service.listRequestsForMap(RequestListFilter())
assertEquals(REQUEST_NAME, response.items.single().name)
assertEquals("POLYGON ((37.5 55.5, 37.7 55.5, 37.7 55.7, 37.5 55.7, 37.5 55.5))", response.items.single().geometry)
assertEquals(REQUEST_IMPORTANCE, response.items.single().importance)
assertEquals(50.0, response.items.single().coveragePercent)
}
@Test
fun `create request rejects duplicate id without touching existing request state`() {
doReturn(true)
@@ -254,8 +280,8 @@ class RequestServiceTest {
verify(requestCellRepository).deleteByRequestId(REQUEST_ID)
}
private fun createRequestDto(): CreateRequestRequestDto {
return CreateRequestRequestDto(
private fun createRequestDto(): CreateRequestDto {
return CreateRequestDto(
id = REQUEST_ID,
name = REQUEST_NAME,
geometry = "POLYGON ((37.5 55.5, 37.7 55.5, 37.7 55.7, 37.5 55.7, 37.5 55.5))",