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:
+1
-1
@@ -50,7 +50,7 @@ class EarthGridService(webClientBuilderProvider: ObjectProvider<WebClient.Builde
|
|||||||
val params = mutableListOf("minImportance=$REQUEST_GRID_MIN_IMPORTANCE")
|
val params = mutableListOf("minImportance=$REQUEST_GRID_MIN_IMPORTANCE")
|
||||||
countLat?.let { params += "countLat=$it" }
|
countLat?.let { params += "countLat=$it" }
|
||||||
countLong?.let { params += "countLong=$it" }
|
countLong?.let { params += "countLong=$it" }
|
||||||
return "/v1/cells/with-requests?${params.joinToString("&")}"
|
return "/v1/cells/priority-map?${params.joinToString("&")}"
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun CellWithRequestsResponseDto.toEarthCellWithRequestsDto(): EarthCellWithRequestsDTO =
|
private fun CellWithRequestsResponseDto.toEarthCellWithRequestsDto(): EarthCellWithRequestsDTO =
|
||||||
|
|||||||
+4
-4
@@ -33,7 +33,7 @@ class EarthGridServiceTest {
|
|||||||
val cell = cells.single()
|
val cell = cells.single()
|
||||||
val request = cell.requests.single()
|
val request = cell.requests.single()
|
||||||
|
|
||||||
assertEquals("/v1/cells/with-requests", requestedUris.single().path)
|
assertEquals("/v1/cells/priority-map", requestedUris.single().path)
|
||||||
assertEquals("minImportance=0.001", requestedUris.single().query)
|
assertEquals("minImportance=0.001", requestedUris.single().query)
|
||||||
assertFalse(requestedUris.any { uri -> uri.path == "/api/earth-grid/with-requests" })
|
assertFalse(requestedUris.any { uri -> uri.path == "/api/earth-grid/with-requests" })
|
||||||
assertEquals(1L, cell.id)
|
assertEquals(1L, cell.id)
|
||||||
@@ -55,7 +55,7 @@ class EarthGridServiceTest {
|
|||||||
|
|
||||||
earthGridService().cells(countLat = 12, countLong = 24).toList()
|
earthGridService().cells(countLat = 12, countLong = 24).toList()
|
||||||
|
|
||||||
assertEquals("/v1/cells/with-requests", requestedUris.single().path)
|
assertEquals("/v1/cells/priority-map", requestedUris.single().path)
|
||||||
assertEquals("minImportance=0.001&countLat=12&countLong=24", requestedUris.single().query)
|
assertEquals("minImportance=0.001&countLat=12&countLong=24", requestedUris.single().query)
|
||||||
assertFalse(requestedUris.any { uri -> uri.path == "/api/earth-grid/with-requests" })
|
assertFalse(requestedUris.any { uri -> uri.path == "/api/earth-grid/with-requests" })
|
||||||
}
|
}
|
||||||
@@ -93,7 +93,7 @@ class EarthGridServiceTest {
|
|||||||
}.cells().toList()
|
}.cells().toList()
|
||||||
|
|
||||||
assertEquals(itemCount, cells.size)
|
assertEquals(itemCount, cells.size)
|
||||||
assertEquals("/v1/cells/with-requests", requestedUris.single().path)
|
assertEquals("/v1/cells/priority-map", requestedUris.single().path)
|
||||||
assertEquals("minImportance=0.001", requestedUris.single().query)
|
assertEquals("minImportance=0.001", requestedUris.single().query)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,7 +128,7 @@ class EarthGridServiceTest {
|
|||||||
responseBody: String
|
responseBody: String
|
||||||
): HttpServer =
|
): HttpServer =
|
||||||
HttpServer.create(InetSocketAddress(0), 0).apply {
|
HttpServer.create(InetSocketAddress(0), 0).apply {
|
||||||
createContext("/v1/cells/with-requests") { exchange ->
|
createContext("/v1/cells/priority-map") { exchange ->
|
||||||
requestedUris += exchange.requestURI
|
requestedUris += exchange.requestURI
|
||||||
exchange.responseHeaders.add("Content-Type", "application/json")
|
exchange.responseHeaders.add("Content-Type", "application/json")
|
||||||
exchange.sendResponseHeaders(200, responseBody.toByteArray().size.toLong())
|
exchange.sendResponseHeaders(200, responseBody.toByteArray().size.toLong())
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ info:
|
|||||||
- заявка создается через POST /v1/requests;
|
- заявка создается через POST /v1/requests;
|
||||||
- чтение одной заявки выполняется через GET /v1/requests/{id};
|
- чтение одной заявки выполняется через GET /v1/requests/{id};
|
||||||
- чтение списка заявок выполняется через GET /v1/requests;
|
- чтение списка заявок выполняется через GET /v1/requests;
|
||||||
|
- чтение списка заявок с geometry выполняется через GET /v1/requests/map;
|
||||||
- удаление заявки выполняется через DELETE /v1/requests/{id};
|
- удаление заявки выполняется через DELETE /v1/requests/{id};
|
||||||
- удаление является мягким: заявка получает status = DELETED и deletedAt;
|
- удаление является мягким: заявка получает status = DELETED и deletedAt;
|
||||||
- заявка должна содержать хотя бы один payload-блок: optics или rsa;
|
- заявка должна содержать хотя бы один payload-блок: optics или rsa;
|
||||||
@@ -106,14 +107,15 @@ paths:
|
|||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/components/schemas/ErrorResponse'
|
$ref: '#/components/schemas/ErrorResponse'
|
||||||
/v1/cells/with-requests:
|
/v1/cells/priority-map:
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
- Cells
|
- Cells
|
||||||
summary: Получить ячейки сетки с фрагментами заявок
|
summary: Получить ячейки сетки с фрагментами заявок
|
||||||
description: |
|
description: |
|
||||||
Возвращает список ячеек сетки вместе с фрагментами заявок, пересекающими каждую ячейку.
|
Возвращает список ячеек сетки вместе с фрагментами заявок, пересекающими каждую ячейку.
|
||||||
operationId: listCellsWithRequests
|
Используется для построения тепловой карты приоритетов.
|
||||||
|
operationId: listCellsPriorityMap
|
||||||
parameters:
|
parameters:
|
||||||
- name: minImportance
|
- name: minImportance
|
||||||
in: query
|
in: query
|
||||||
@@ -143,7 +145,7 @@ paths:
|
|||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/components/schemas/CellsWithRequestsResponse'
|
$ref: '#/components/schemas/CellPriorityMapResponse'
|
||||||
'400':
|
'400':
|
||||||
description: Некорректные query parameters
|
description: Некорректные query parameters
|
||||||
content:
|
content:
|
||||||
@@ -304,7 +306,8 @@ paths:
|
|||||||
Возвращает постраничный список заявок.
|
Возвращает постраничный список заявок.
|
||||||
|
|
||||||
По умолчанию удаленные заявки не возвращаются. Для технического поиска можно передать includeDeleted=true.
|
По умолчанию удаленные заявки не возвращаются. Для технического поиска можно передать includeDeleted=true.
|
||||||
Полная geometry не возвращается в списке по умолчанию; для полной заявки используйте GET /v1/requests/{id}.
|
Полная geometry не возвращается в списке по умолчанию; для списка с geometry используйте GET /v1/requests/map,
|
||||||
|
для полной заявки используйте GET /v1/requests/{id}.
|
||||||
operationId: listRequests
|
operationId: listRequests
|
||||||
parameters:
|
parameters:
|
||||||
- name: status
|
- name: status
|
||||||
@@ -415,7 +418,127 @@ paths:
|
|||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/components/schemas/ErrorResponse'
|
$ref: '#/components/schemas/ErrorResponse'
|
||||||
/v1/requests/{requestId}/with-cells:
|
/v1/requests/map:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- Requests
|
||||||
|
summary: Получить список заявок с геометрией для карты
|
||||||
|
description: |
|
||||||
|
Возвращает постраничный список заявок с полной geometry в WKT.
|
||||||
|
|
||||||
|
Endpoint использует те же фильтры и сортировку, что GET /v1/requests, но возвращает расширенную read-модель.
|
||||||
|
Используйте его только там, где клиенту действительно нужна геометрия списка (например, для отображения на карте).
|
||||||
|
operationId: listRequestsForMap
|
||||||
|
parameters:
|
||||||
|
- name: status
|
||||||
|
in: query
|
||||||
|
required: false
|
||||||
|
description: Фильтр по статусу заявки
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/RequestStatus'
|
||||||
|
- name: surveyType
|
||||||
|
in: query
|
||||||
|
required: false
|
||||||
|
description: Фильтр по вычисленному типу заявки
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/SurveyType'
|
||||||
|
- name: kpp
|
||||||
|
in: query
|
||||||
|
required: false
|
||||||
|
description: Фильтр по номеру КПП. Возвращает заявки, содержащие указанный КПП.
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
example: 1
|
||||||
|
- name: highPriorityTransmit
|
||||||
|
in: query
|
||||||
|
required: false
|
||||||
|
description: Фильтр по признаку высокоприоритетной передачи
|
||||||
|
schema:
|
||||||
|
type: boolean
|
||||||
|
- name: beginFrom
|
||||||
|
in: query
|
||||||
|
required: false
|
||||||
|
description: Нижняя граница beginDateTime, включительно
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
format: date-time
|
||||||
|
- name: beginTo
|
||||||
|
in: query
|
||||||
|
required: false
|
||||||
|
description: Верхняя граница beginDateTime, включительно
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
format: date-time
|
||||||
|
- name: endFrom
|
||||||
|
in: query
|
||||||
|
required: false
|
||||||
|
description: Нижняя граница endDateTime, включительно
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
format: date-time
|
||||||
|
- name: endTo
|
||||||
|
in: query
|
||||||
|
required: false
|
||||||
|
description: Верхняя граница endDateTime, включительно
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
format: date-time
|
||||||
|
- name: includeDeleted
|
||||||
|
in: query
|
||||||
|
required: false
|
||||||
|
description: Включать soft-deleted заявки в результат
|
||||||
|
schema:
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
|
- name: page
|
||||||
|
in: query
|
||||||
|
required: false
|
||||||
|
description: Номер страницы, начиная с 0
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
minimum: 0
|
||||||
|
default: 0
|
||||||
|
- name: size
|
||||||
|
in: query
|
||||||
|
required: false
|
||||||
|
description: Размер страницы
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
minimum: 1
|
||||||
|
maximum: 500
|
||||||
|
default: 50
|
||||||
|
- name: sort
|
||||||
|
in: query
|
||||||
|
required: false
|
||||||
|
description: Сортировка в формате field,direction. Разрешенные поля зависят от реализации.
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
default: createdAt,desc
|
||||||
|
examples:
|
||||||
|
createdDesc:
|
||||||
|
value: createdAt,desc
|
||||||
|
beginAsc:
|
||||||
|
value: beginDateTime,asc
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: Список заявок с геометрией
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/RequestMapPageResponse'
|
||||||
|
'400':
|
||||||
|
description: Некорректные query parameters
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/ErrorResponse'
|
||||||
|
'500':
|
||||||
|
description: Внутренняя ошибка сервера
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/ErrorResponse'
|
||||||
|
/v1/requests/{id}/cells:
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
- Cells
|
- Cells
|
||||||
@@ -425,7 +548,7 @@ paths:
|
|||||||
Возвращает заявку и проекцию ее пересечений с ячейками сетки.
|
Возвращает заявку и проекцию ее пересечений с ячейками сетки.
|
||||||
operationId: getRequestWithCells
|
operationId: getRequestWithCells
|
||||||
parameters:
|
parameters:
|
||||||
- $ref: '#/components/parameters/RequestIdWithCellsPathParam'
|
- $ref: '#/components/parameters/RequestIdPathParam'
|
||||||
responses:
|
responses:
|
||||||
'200':
|
'200':
|
||||||
description: Заявка с привязанными ячейками
|
description: Заявка с привязанными ячейками
|
||||||
@@ -500,7 +623,6 @@ paths:
|
|||||||
$ref: '#/components/schemas/DeleteRequestResponse'
|
$ref: '#/components/schemas/DeleteRequestResponse'
|
||||||
example:
|
example:
|
||||||
id: 3fa85f64-5717-4562-b3fc-2c963f66afa6
|
id: 3fa85f64-5717-4562-b3fc-2c963f66afa6
|
||||||
status: DELETED
|
|
||||||
deletedAt: '2026-05-19T13:00:00Z'
|
deletedAt: '2026-05-19T13:00:00Z'
|
||||||
'404':
|
'404':
|
||||||
description: Заявка не найдена
|
description: Заявка не найдена
|
||||||
@@ -609,15 +731,6 @@ components:
|
|||||||
type: string
|
type: string
|
||||||
format: uuid
|
format: uuid
|
||||||
example: 3fa85f64-5717-4562-b3fc-2c963f66afa6
|
example: 3fa85f64-5717-4562-b3fc-2c963f66afa6
|
||||||
RequestIdWithCellsPathParam:
|
|
||||||
name: requestId
|
|
||||||
in: path
|
|
||||||
required: true
|
|
||||||
description: Идентификатор заявки
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
format: uuid
|
|
||||||
example: 3fa85f64-5717-4562-b3fc-2c963f66afa6
|
|
||||||
schemas:
|
schemas:
|
||||||
CreateRequestRequest:
|
CreateRequestRequest:
|
||||||
type: object
|
type: object
|
||||||
@@ -921,12 +1034,125 @@ components:
|
|||||||
minimum: 0
|
minimum: 0
|
||||||
example: 1
|
example: 1
|
||||||
additionalProperties: false
|
additionalProperties: false
|
||||||
|
RequestMapItemResponse:
|
||||||
|
type: object
|
||||||
|
description: Краткая карточка заявки с полной геометрией для GET /v1/requests/map
|
||||||
|
required:
|
||||||
|
- id
|
||||||
|
- name
|
||||||
|
- status
|
||||||
|
- surveyType
|
||||||
|
- geometry
|
||||||
|
- importance
|
||||||
|
- beginDateTime
|
||||||
|
- endDateTime
|
||||||
|
- highPriorityTransmit
|
||||||
|
- coveragePercent
|
||||||
|
- createdAt
|
||||||
|
- updatedAt
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
description: Идентификатор заявки
|
||||||
|
example: 3fa85f64-5717-4562-b3fc-2c963f66afa6
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
minLength: 1
|
||||||
|
maxLength: 255
|
||||||
|
description: Наименование задания.
|
||||||
|
example: Тест1
|
||||||
|
status:
|
||||||
|
$ref: '#/components/schemas/RequestStatus'
|
||||||
|
surveyType:
|
||||||
|
$ref: '#/components/schemas/SurveyType'
|
||||||
|
geometry:
|
||||||
|
type: string
|
||||||
|
format: wkt
|
||||||
|
description: Полная геометрия заявки в формате WKT
|
||||||
|
example: POLYGON ((37.5 55.5, 37.7 55.5, 37.7 55.7, 37.5 55.7, 37.5 55.5))
|
||||||
|
importance:
|
||||||
|
type: number
|
||||||
|
format: double
|
||||||
|
minimum: 0
|
||||||
|
description: Важность заявки, используемая при расчете важности ячеек сетки.
|
||||||
|
example: 10.0
|
||||||
|
beginDateTime:
|
||||||
|
type: string
|
||||||
|
format: date-time
|
||||||
|
example: '2026-01-01T00:00:00Z'
|
||||||
|
endDateTime:
|
||||||
|
type: string
|
||||||
|
format: date-time
|
||||||
|
example: '2026-01-31T23:59:59Z'
|
||||||
|
kpp:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: integer
|
||||||
|
description: Список номеров КПП для сброса
|
||||||
|
example: [1, 2, 3]
|
||||||
|
highPriorityTransmit:
|
||||||
|
type: boolean
|
||||||
|
example: false
|
||||||
|
coveragePercent:
|
||||||
|
type: number
|
||||||
|
format: double
|
||||||
|
minimum: 0
|
||||||
|
maximum: 100
|
||||||
|
description: Текущий процент покрытия заявки
|
||||||
|
example: 35.5
|
||||||
|
createdAt:
|
||||||
|
type: string
|
||||||
|
format: date-time
|
||||||
|
example: '2026-05-19T12:00:00Z'
|
||||||
|
updatedAt:
|
||||||
|
type: string
|
||||||
|
format: date-time
|
||||||
|
example: '2026-05-19T12:30:00Z'
|
||||||
|
deletedAt:
|
||||||
|
type: string
|
||||||
|
format: date-time
|
||||||
|
nullable: true
|
||||||
|
description: Дата-время soft delete. Обычно отсутствует/null при includeDeleted=false.
|
||||||
|
example: null
|
||||||
|
additionalProperties: false
|
||||||
|
RequestMapPageResponse:
|
||||||
|
type: object
|
||||||
|
description: Постраничный список заявок с полной геометрией для GET /v1/requests/map
|
||||||
|
required:
|
||||||
|
- items
|
||||||
|
- page
|
||||||
|
- size
|
||||||
|
- totalItems
|
||||||
|
- totalPages
|
||||||
|
properties:
|
||||||
|
items:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/RequestMapItemResponse'
|
||||||
|
page:
|
||||||
|
type: integer
|
||||||
|
minimum: 0
|
||||||
|
example: 0
|
||||||
|
size:
|
||||||
|
type: integer
|
||||||
|
minimum: 1
|
||||||
|
example: 50
|
||||||
|
totalItems:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
minimum: 0
|
||||||
|
example: 1
|
||||||
|
totalPages:
|
||||||
|
type: integer
|
||||||
|
minimum: 0
|
||||||
|
example: 1
|
||||||
|
additionalProperties: false
|
||||||
DeleteRequestResponse:
|
DeleteRequestResponse:
|
||||||
type: object
|
type: object
|
||||||
description: Ответ на soft delete заявки
|
description: Ответ на soft delete заявки
|
||||||
required:
|
required:
|
||||||
- id
|
- id
|
||||||
- status
|
|
||||||
- deletedAt
|
- deletedAt
|
||||||
properties:
|
properties:
|
||||||
id:
|
id:
|
||||||
@@ -934,12 +1160,6 @@ components:
|
|||||||
format: uuid
|
format: uuid
|
||||||
description: Идентификатор заявки
|
description: Идентификатор заявки
|
||||||
example: 3fa85f64-5717-4562-b3fc-2c963f66afa6
|
example: 3fa85f64-5717-4562-b3fc-2c963f66afa6
|
||||||
status:
|
|
||||||
type: string
|
|
||||||
enum:
|
|
||||||
- DELETED
|
|
||||||
description: Итоговый статус после soft delete
|
|
||||||
example: DELETED
|
|
||||||
deletedAt:
|
deletedAt:
|
||||||
type: string
|
type: string
|
||||||
format: date-time
|
format: date-time
|
||||||
@@ -1091,9 +1311,9 @@ components:
|
|||||||
description: Важность заявки для расчета важности ячейки
|
description: Важность заявки для расчета важности ячейки
|
||||||
example: 10.0
|
example: 10.0
|
||||||
additionalProperties: false
|
additionalProperties: false
|
||||||
CellsWithRequestsResponse:
|
CellPriorityMapResponse:
|
||||||
type: object
|
type: object
|
||||||
description: Список ячеек сетки с фрагментами заявок
|
description: Список ячеек сетки с фрагментами заявок для GET /v1/cells/priority-map
|
||||||
required:
|
required:
|
||||||
- items
|
- items
|
||||||
properties:
|
properties:
|
||||||
|
|||||||
+5
-5
@@ -1,7 +1,7 @@
|
|||||||
package org.nstart.dep265.requestservice.controller
|
package org.nstart.dep265.requestservice.controller
|
||||||
|
|
||||||
|
import org.nstart.dep265.requestservice.dto.CellPriorityMapResponseDto
|
||||||
import org.nstart.dep265.requestservice.dto.CellsListResponseDto
|
import org.nstart.dep265.requestservice.dto.CellsListResponseDto
|
||||||
import org.nstart.dep265.requestservice.dto.CellsWithRequestsResponseDto
|
|
||||||
import org.nstart.dep265.requestservice.service.CellsQueryService
|
import org.nstart.dep265.requestservice.service.CellsQueryService
|
||||||
import org.springframework.web.bind.annotation.GetMapping
|
import org.springframework.web.bind.annotation.GetMapping
|
||||||
import org.springframework.web.bind.annotation.RequestMapping
|
import org.springframework.web.bind.annotation.RequestMapping
|
||||||
@@ -32,13 +32,13 @@ class CellsController(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/with-requests")
|
@GetMapping("/priority-map")
|
||||||
fun listCellsWithRequests(
|
fun listCellsPriorityMap(
|
||||||
@RequestParam(required = false) minImportance: Double?,
|
@RequestParam(required = false) minImportance: Double?,
|
||||||
@RequestParam(required = false) countLat: Int?,
|
@RequestParam(required = false) countLat: Int?,
|
||||||
@RequestParam(required = false) countLong: Int?,
|
@RequestParam(required = false) countLong: Int?,
|
||||||
): CellsWithRequestsResponseDto {
|
): CellPriorityMapResponseDto {
|
||||||
return cellsQueryService.listCellsWithRequests(
|
return cellsQueryService.listCellsPriorityMap(
|
||||||
minImportance = minImportance,
|
minImportance = minImportance,
|
||||||
countLat = countLat,
|
countLat = countLat,
|
||||||
countLong = countLong,
|
countLong = countLong,
|
||||||
|
|||||||
+40
-7
@@ -1,11 +1,12 @@
|
|||||||
package org.nstart.dep265.requestservice.controller
|
package org.nstart.dep265.requestservice.controller
|
||||||
|
|
||||||
import jakarta.validation.Valid
|
import jakarta.validation.Valid
|
||||||
import org.nstart.dep265.requestservice.dto.CreateRequestRequestDto
|
import org.nstart.dep265.requestservice.dto.CreateRequestDto
|
||||||
import org.nstart.dep265.requestservice.dto.CreateRequestResponseDto
|
import org.nstart.dep265.requestservice.dto.CreateRequestResponseDto
|
||||||
import org.nstart.dep265.requestservice.dto.DeleteRequestResponseDto
|
import org.nstart.dep265.requestservice.dto.DeleteRequestResponseDto
|
||||||
import org.nstart.dep265.requestservice.dto.ListRequestsQueryDto
|
import org.nstart.dep265.requestservice.dto.RequestListFilter
|
||||||
import org.nstart.dep265.requestservice.dto.RequestListResponseDto
|
import org.nstart.dep265.requestservice.dto.RequestListResponseDto
|
||||||
|
import org.nstart.dep265.requestservice.dto.RequestMapPageDto
|
||||||
import org.nstart.dep265.requestservice.dto.RequestResponseDto
|
import org.nstart.dep265.requestservice.dto.RequestResponseDto
|
||||||
import org.nstart.dep265.requestservice.dto.RequestStatusDto
|
import org.nstart.dep265.requestservice.dto.RequestStatusDto
|
||||||
import org.nstart.dep265.requestservice.dto.RequestWithCellsResponseDto
|
import org.nstart.dep265.requestservice.dto.RequestWithCellsResponseDto
|
||||||
@@ -30,7 +31,7 @@ class RequestController(
|
|||||||
private val requestService: RequestService,
|
private val requestService: RequestService,
|
||||||
) {
|
) {
|
||||||
@PostMapping
|
@PostMapping
|
||||||
fun createRequest(@Valid @RequestBody request: CreateRequestRequestDto): ResponseEntity<CreateRequestResponseDto> {
|
fun createRequest(@Valid @RequestBody request: CreateRequestDto): ResponseEntity<CreateRequestResponseDto> {
|
||||||
return ResponseEntity.status(201).body(requestService.createRequest(request))
|
return ResponseEntity.status(201).body(requestService.createRequest(request))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,7 +50,7 @@ class RequestController(
|
|||||||
@RequestParam(defaultValue = "50") size: Int,
|
@RequestParam(defaultValue = "50") size: Int,
|
||||||
@RequestParam(defaultValue = "createdAt,desc") sort: String,
|
@RequestParam(defaultValue = "createdAt,desc") sort: String,
|
||||||
): RequestListResponseDto {
|
): RequestListResponseDto {
|
||||||
val query = ListRequestsQueryDto(
|
val query = RequestListFilter(
|
||||||
status = status,
|
status = status,
|
||||||
surveyType = surveyType,
|
surveyType = surveyType,
|
||||||
kpp = kpp,
|
kpp = kpp,
|
||||||
@@ -66,6 +67,38 @@ class RequestController(
|
|||||||
return requestService.listRequests(query)
|
return requestService.listRequests(query)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/map")
|
||||||
|
fun listRequestsForMap(
|
||||||
|
@RequestParam(required = false) status: RequestStatusDto?,
|
||||||
|
@RequestParam(required = false) surveyType: SurveyTypeDto?,
|
||||||
|
@RequestParam(required = false) kpp: Int?,
|
||||||
|
@RequestParam(required = false) highPriorityTransmit: Boolean?,
|
||||||
|
@RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) beginFrom: OffsetDateTime?,
|
||||||
|
@RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) beginTo: OffsetDateTime?,
|
||||||
|
@RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) endFrom: OffsetDateTime?,
|
||||||
|
@RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) endTo: OffsetDateTime?,
|
||||||
|
@RequestParam(defaultValue = "false") includeDeleted: Boolean,
|
||||||
|
@RequestParam(defaultValue = "0") page: Int,
|
||||||
|
@RequestParam(defaultValue = "50") size: Int,
|
||||||
|
@RequestParam(defaultValue = "createdAt,desc") sort: String,
|
||||||
|
): RequestMapPageDto {
|
||||||
|
val query = RequestListFilter(
|
||||||
|
status = status,
|
||||||
|
surveyType = surveyType,
|
||||||
|
kpp = kpp,
|
||||||
|
highPriorityTransmit = highPriorityTransmit,
|
||||||
|
beginFrom = beginFrom,
|
||||||
|
beginTo = beginTo,
|
||||||
|
endFrom = endFrom,
|
||||||
|
endTo = endTo,
|
||||||
|
includeDeleted = includeDeleted,
|
||||||
|
page = page,
|
||||||
|
size = size,
|
||||||
|
sort = sort,
|
||||||
|
)
|
||||||
|
return requestService.listRequestsForMap(query)
|
||||||
|
}
|
||||||
|
|
||||||
@GetMapping("/{id}")
|
@GetMapping("/{id}")
|
||||||
fun getRequestById(@PathVariable id: UUID): ResponseEntity<RequestResponseDto> {
|
fun getRequestById(@PathVariable id: UUID): ResponseEntity<RequestResponseDto> {
|
||||||
return requestService.getRequestById(id)
|
return requestService.getRequestById(id)
|
||||||
@@ -73,9 +106,9 @@ class RequestController(
|
|||||||
?: ResponseEntity.notFound().build()
|
?: ResponseEntity.notFound().build()
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/{requestId}/with-cells")
|
@GetMapping("/{id}/cells")
|
||||||
fun getRequestWithCells(@PathVariable requestId: UUID): ResponseEntity<RequestWithCellsResponseDto> {
|
fun getRequestWithCells(@PathVariable id: UUID): ResponseEntity<RequestWithCellsResponseDto> {
|
||||||
return requestService.getRequestWithCells(requestId)
|
return requestService.getRequestWithCells(id)
|
||||||
?.let { response -> ResponseEntity.ok(response) }
|
?.let { response -> ResponseEntity.ok(response) }
|
||||||
?: ResponseEntity.notFound().build()
|
?: ResponseEntity.notFound().build()
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -43,7 +43,7 @@ data class CellsListResponseDto(
|
|||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Фрагмент заявки внутри ячейки сетки для GET /v1/cells/with-requests.
|
* Фрагмент заявки внутри ячейки сетки для GET /v1/cells/priority-map.
|
||||||
*/
|
*/
|
||||||
data class CellRequestFragmentResponseDto(
|
data class CellRequestFragmentResponseDto(
|
||||||
/** Идентификатор заявки. */
|
/** Идентификатор заявки. */
|
||||||
@@ -60,7 +60,7 @@ data class CellRequestFragmentResponseDto(
|
|||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ячейка сетки с фрагментами заявок для GET /v1/cells/with-requests.
|
* Ячейка сетки с фрагментами заявок для GET /v1/cells/priority-map.
|
||||||
*/
|
*/
|
||||||
data class CellWithRequestsResponseDto(
|
data class CellWithRequestsResponseDto(
|
||||||
/** Номер ячейки сетки. */
|
/** Номер ячейки сетки. */
|
||||||
@@ -83,9 +83,9 @@ data class CellWithRequestsResponseDto(
|
|||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Список ячеек сетки с фрагментами заявок.
|
* Список ячеек сетки с фрагментами заявок для GET /v1/cells/priority-map.
|
||||||
*/
|
*/
|
||||||
data class CellsWithRequestsResponseDto(
|
data class CellPriorityMapResponseDto(
|
||||||
/** Ячейки сетки с привязанными request_cells fragments. */
|
/** Ячейки сетки с привязанными request_cells fragments. */
|
||||||
val items: List<CellWithRequestsResponseDto>,
|
val items: List<CellWithRequestsResponseDto>,
|
||||||
)
|
)
|
||||||
|
|||||||
+70
-15
@@ -27,7 +27,7 @@ abstract class StrictRequestApiDto {
|
|||||||
/**
|
/**
|
||||||
* Тело запроса на создание заявки по OpenAPI.
|
* Тело запроса на создание заявки по OpenAPI.
|
||||||
*/
|
*/
|
||||||
data class CreateRequestRequestDto(
|
data class CreateRequestDto(
|
||||||
/** Внешний идентификатор заявки. */
|
/** Внешний идентификатор заявки. */
|
||||||
@field:NotNull
|
@field:NotNull
|
||||||
val id: UUID,
|
val id: UUID,
|
||||||
@@ -68,7 +68,6 @@ data class CreateRequestRequestDto(
|
|||||||
@field:Valid
|
@field:Valid
|
||||||
val rsa: RsaParamsDto? = null,
|
val rsa: RsaParamsDto? = null,
|
||||||
) : StrictRequestApiDto() {
|
) : StrictRequestApiDto() {
|
||||||
/** В create-запросе должен быть указан хотя бы один payload-блок съемки. */
|
|
||||||
@get:AssertTrue(message = "Должен быть указан хотя бы один блок съемки: optics или rsa")
|
@get:AssertTrue(message = "Должен быть указан хотя бы один блок съемки: optics или rsa")
|
||||||
@get:JsonIgnore
|
@get:JsonIgnore
|
||||||
val hasSurveyPayload: Boolean
|
val hasSurveyPayload: Boolean
|
||||||
@@ -215,6 +214,73 @@ data class RequestListResponseDto(
|
|||||||
val totalPages: Int,
|
val totalPages: Int,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Краткая карточка заявки с геометрией для GET /v1/requests/map.
|
||||||
|
*/
|
||||||
|
data class RequestMapItemDto(
|
||||||
|
/** Идентификатор заявки. */
|
||||||
|
val id: UUID,
|
||||||
|
|
||||||
|
/** Наименование задания. */
|
||||||
|
val name: String,
|
||||||
|
|
||||||
|
/** Текущий статус заявки. */
|
||||||
|
val status: RequestStatusDto,
|
||||||
|
|
||||||
|
/** Вычисленный тип заявки. */
|
||||||
|
val surveyType: SurveyTypeDto,
|
||||||
|
|
||||||
|
/** Полная геометрия заявки в WKT. */
|
||||||
|
val geometry: String,
|
||||||
|
|
||||||
|
/** Важность заявки для расчета важности ячеек сетки. */
|
||||||
|
val importance: Double,
|
||||||
|
|
||||||
|
/** Начало временного окна выполнения заявки. */
|
||||||
|
val beginDateTime: OffsetDateTime,
|
||||||
|
|
||||||
|
/** Окончание временного окна выполнения заявки. */
|
||||||
|
val endDateTime: OffsetDateTime,
|
||||||
|
|
||||||
|
/** Список номеров КПП для сброса. */
|
||||||
|
val kpp: List<Int> = emptyList(),
|
||||||
|
|
||||||
|
/** Признак высокоприоритетной передачи. */
|
||||||
|
val highPriorityTransmit: Boolean,
|
||||||
|
|
||||||
|
/** Текущий процент покрытия заявки. */
|
||||||
|
val coveragePercent: Double,
|
||||||
|
|
||||||
|
/** Время создания заявки. */
|
||||||
|
val createdAt: OffsetDateTime,
|
||||||
|
|
||||||
|
/** Время последнего обновления заявки. */
|
||||||
|
val updatedAt: OffsetDateTime,
|
||||||
|
|
||||||
|
/** Время soft delete, если заявка удалена. */
|
||||||
|
val deletedAt: OffsetDateTime? = null,
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Постраничный список заявок с полной геометрией для GET /v1/requests/map.
|
||||||
|
*/
|
||||||
|
data class RequestMapPageDto(
|
||||||
|
/** Элементы текущей страницы. */
|
||||||
|
val items: List<RequestMapItemDto>,
|
||||||
|
|
||||||
|
/** Номер страницы, начиная с 0. */
|
||||||
|
val page: Int,
|
||||||
|
|
||||||
|
/** Размер страницы. */
|
||||||
|
val size: Int,
|
||||||
|
|
||||||
|
/** Общее количество элементов. */
|
||||||
|
val totalItems: Long,
|
||||||
|
|
||||||
|
/** Общее количество страниц. */
|
||||||
|
val totalPages: Int,
|
||||||
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ячейка, связанная с заявкой через request_cells projection.
|
* Ячейка, связанная с заявкой через request_cells projection.
|
||||||
*/
|
*/
|
||||||
@@ -250,9 +316,6 @@ data class DeleteRequestResponseDto(
|
|||||||
/** Идентификатор заявки. */
|
/** Идентификатор заявки. */
|
||||||
val id: UUID,
|
val id: UUID,
|
||||||
|
|
||||||
/** Итоговый статус после удаления. */
|
|
||||||
val status: DeleteRequestStatusDto,
|
|
||||||
|
|
||||||
/** Время soft delete. */
|
/** Время soft delete. */
|
||||||
val deletedAt: OffsetDateTime,
|
val deletedAt: OffsetDateTime,
|
||||||
)
|
)
|
||||||
@@ -342,9 +405,9 @@ data class ErrorDetailDto(
|
|||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Query parameters list endpoint.
|
* Query parameters для list endpoint.
|
||||||
*/
|
*/
|
||||||
data class ListRequestsQueryDto(
|
data class RequestListFilter(
|
||||||
/** Фильтр по статусу заявки. */
|
/** Фильтр по статусу заявки. */
|
||||||
val status: RequestStatusDto? = null,
|
val status: RequestStatusDto? = null,
|
||||||
|
|
||||||
@@ -405,14 +468,6 @@ enum class RequestStatusDto {
|
|||||||
DELETED,
|
DELETED,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Статус ответа delete endpoint.
|
|
||||||
*/
|
|
||||||
enum class DeleteRequestStatusDto {
|
|
||||||
/** Заявка удалена или уже была удалена ранее. */
|
|
||||||
DELETED,
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Вычисленный тип заявки по наличию optics/rsa.
|
* Вычисленный тип заявки по наличию optics/rsa.
|
||||||
*/
|
*/
|
||||||
|
|||||||
+4
-4
@@ -4,7 +4,7 @@ import org.nstart.dep265.requestservice.dto.CellRequestFragmentResponseDto
|
|||||||
import org.nstart.dep265.requestservice.dto.CellSummaryResponseDto
|
import org.nstart.dep265.requestservice.dto.CellSummaryResponseDto
|
||||||
import org.nstart.dep265.requestservice.dto.CellWithRequestsResponseDto
|
import org.nstart.dep265.requestservice.dto.CellWithRequestsResponseDto
|
||||||
import org.nstart.dep265.requestservice.dto.CellsListResponseDto
|
import org.nstart.dep265.requestservice.dto.CellsListResponseDto
|
||||||
import org.nstart.dep265.requestservice.dto.CellsWithRequestsResponseDto
|
import org.nstart.dep265.requestservice.dto.CellPriorityMapResponseDto
|
||||||
import org.nstart.dep265.requestservice.entity.EarthCellEntity
|
import org.nstart.dep265.requestservice.entity.EarthCellEntity
|
||||||
import org.nstart.dep265.requestservice.entity.RequestCellEntity
|
import org.nstart.dep265.requestservice.entity.RequestCellEntity
|
||||||
import org.nstart.dep265.requestservice.repository.EarthCellRepository
|
import org.nstart.dep265.requestservice.repository.EarthCellRepository
|
||||||
@@ -49,11 +49,11 @@ class CellsQueryService(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
fun listCellsWithRequests(
|
fun listCellsPriorityMap(
|
||||||
minImportance: Double?,
|
minImportance: Double?,
|
||||||
countLat: Int?,
|
countLat: Int?,
|
||||||
countLong: Int?,
|
countLong: Int?,
|
||||||
): CellsWithRequestsResponseDto {
|
): CellPriorityMapResponseDto {
|
||||||
validateWithRequestsQuery(minImportance, countLat, countLong)
|
validateWithRequestsQuery(minImportance, countLat, countLong)
|
||||||
|
|
||||||
val items = if (countLat == null && countLong == null) {
|
val items = if (countLat == null && countLong == null) {
|
||||||
@@ -68,7 +68,7 @@ class CellsQueryService(
|
|||||||
.map { earthCell -> earthCell.toWithRequestsResponse() }
|
.map { earthCell -> earthCell.toWithRequestsResponse() }
|
||||||
}
|
}
|
||||||
|
|
||||||
return CellsWithRequestsResponseDto(items = items)
|
return CellPriorityMapResponseDto(items = items)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun validateQuery(
|
private fun validateQuery(
|
||||||
|
|||||||
+55
-20
@@ -4,18 +4,19 @@ import jakarta.persistence.EntityExistsException
|
|||||||
import jakarta.persistence.EntityManager
|
import jakarta.persistence.EntityManager
|
||||||
import jakarta.persistence.PersistenceException
|
import jakarta.persistence.PersistenceException
|
||||||
import org.hibernate.exception.ConstraintViolationException
|
import org.hibernate.exception.ConstraintViolationException
|
||||||
import org.nstart.dep265.requestservice.dto.CreateRequestRequestDto
|
import org.nstart.dep265.requestservice.dto.CreateRequestDto
|
||||||
import org.nstart.dep265.requestservice.dto.CreateRequestResponseDto
|
import org.nstart.dep265.requestservice.dto.CreateRequestResponseDto
|
||||||
import org.nstart.dep265.requestservice.dto.CoverageStateDto
|
import org.nstart.dep265.requestservice.dto.CoverageStateDto
|
||||||
import org.nstart.dep265.requestservice.dto.DeleteRequestResponseDto
|
import org.nstart.dep265.requestservice.dto.DeleteRequestResponseDto
|
||||||
import org.nstart.dep265.requestservice.dto.DeleteRequestStatusDto
|
import org.nstart.dep265.requestservice.dto.RequestListFilter
|
||||||
import org.nstart.dep265.requestservice.dto.ListRequestsQueryDto
|
|
||||||
import org.nstart.dep265.requestservice.dto.OpticsParamsDto
|
import org.nstart.dep265.requestservice.dto.OpticsParamsDto
|
||||||
import org.nstart.dep265.requestservice.dto.RequestListResponseDto
|
import org.nstart.dep265.requestservice.dto.RequestListResponseDto
|
||||||
import org.nstart.dep265.requestservice.dto.RequestCellResponseDto
|
import org.nstart.dep265.requestservice.dto.RequestCellResponseDto
|
||||||
import org.nstart.dep265.requestservice.dto.RequestResponseDto
|
import org.nstart.dep265.requestservice.dto.RequestResponseDto
|
||||||
import org.nstart.dep265.requestservice.dto.RequestSummaryResponseDto
|
import org.nstart.dep265.requestservice.dto.RequestSummaryResponseDto
|
||||||
import org.nstart.dep265.requestservice.dto.RequestWithCellsResponseDto
|
import org.nstart.dep265.requestservice.dto.RequestWithCellsResponseDto
|
||||||
|
import org.nstart.dep265.requestservice.dto.RequestMapPageDto
|
||||||
|
import org.nstart.dep265.requestservice.dto.RequestMapItemDto
|
||||||
import org.nstart.dep265.requestservice.dto.RequestStatusDto
|
import org.nstart.dep265.requestservice.dto.RequestStatusDto
|
||||||
import org.nstart.dep265.requestservice.dto.RsaParamsDto
|
import org.nstart.dep265.requestservice.dto.RsaParamsDto
|
||||||
import org.nstart.dep265.requestservice.dto.SurveyTypeDto
|
import org.nstart.dep265.requestservice.dto.SurveyTypeDto
|
||||||
@@ -32,6 +33,7 @@ import org.nstart.dep265.requestservice.repository.RequestCellRepository
|
|||||||
import org.nstart.dep265.requestservice.repository.RequestOpticsParamsRepository
|
import org.nstart.dep265.requestservice.repository.RequestOpticsParamsRepository
|
||||||
import org.nstart.dep265.requestservice.repository.RequestRepository
|
import org.nstart.dep265.requestservice.repository.RequestRepository
|
||||||
import org.nstart.dep265.requestservice.repository.RequestRsaParamsRepository
|
import org.nstart.dep265.requestservice.repository.RequestRsaParamsRepository
|
||||||
|
import org.springframework.data.domain.Page
|
||||||
import org.springframework.data.domain.PageRequest
|
import org.springframework.data.domain.PageRequest
|
||||||
import org.springframework.data.domain.Sort
|
import org.springframework.data.domain.Sort
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
@@ -54,7 +56,7 @@ class RequestService(
|
|||||||
private val entityManager: EntityManager,
|
private val entityManager: EntityManager,
|
||||||
) {
|
) {
|
||||||
@Transactional
|
@Transactional
|
||||||
fun createRequest(request: CreateRequestRequestDto): CreateRequestResponseDto {
|
fun createRequest(request: CreateRequestDto): CreateRequestResponseDto {
|
||||||
val requestId = request.id
|
val requestId = request.id
|
||||||
if (requestRepository.existsById(requestId)) {
|
if (requestRepository.existsById(requestId)) {
|
||||||
throw RequestAlreadyExistsException(requestId)
|
throw RequestAlreadyExistsException(requestId)
|
||||||
@@ -105,20 +107,8 @@ class RequestService(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
fun listRequests(query: ListRequestsQueryDto): RequestListResponseDto {
|
fun listRequests(query: RequestListFilter): RequestListResponseDto {
|
||||||
val requests = requestRepository.findRequests(
|
val requests = findRequests(query)
|
||||||
includeDeleted = query.includeDeleted,
|
|
||||||
deletedStatus = RequestStatus.DELETED,
|
|
||||||
status = query.status?.toEntity(),
|
|
||||||
surveyType = query.surveyType?.toEntity(),
|
|
||||||
kpp = query.kpp,
|
|
||||||
highPriorityTransmit = query.highPriorityTransmit,
|
|
||||||
beginFrom = query.beginFrom?.toUtcLocalDateTime(),
|
|
||||||
beginTo = query.beginTo?.toUtcLocalDateTime(),
|
|
||||||
endFrom = query.endFrom?.toUtcLocalDateTime(),
|
|
||||||
endTo = query.endTo?.toUtcLocalDateTime(),
|
|
||||||
pageable = PageRequest.of(query.page, query.size, query.sort.toRequestSort()),
|
|
||||||
)
|
|
||||||
return RequestListResponseDto(
|
return RequestListResponseDto(
|
||||||
items = requests.content.map { request -> request.toSummaryResponse() },
|
items = requests.content.map { request -> request.toSummaryResponse() },
|
||||||
page = query.page,
|
page = query.page,
|
||||||
@@ -128,6 +118,18 @@ class RequestService(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional(readOnly = true)
|
||||||
|
fun listRequestsForMap(query: RequestListFilter): RequestMapPageDto {
|
||||||
|
val requests = findRequests(query)
|
||||||
|
return RequestMapPageDto(
|
||||||
|
items = requests.content.map { request -> request.toMapItemResponse() },
|
||||||
|
page = query.page,
|
||||||
|
size = query.size,
|
||||||
|
totalItems = requests.totalElements,
|
||||||
|
totalPages = requests.totalPages,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
fun getRequestById(id: UUID): RequestResponseDto? {
|
fun getRequestById(id: UUID): RequestResponseDto? {
|
||||||
val request = requestRepository.findById(id).orElse(null) ?: return null
|
val request = requestRepository.findById(id).orElse(null) ?: return null
|
||||||
@@ -160,7 +162,6 @@ class RequestService(
|
|||||||
requestCellRepository.deleteByRequestId(request.id)
|
requestCellRepository.deleteByRequestId(request.id)
|
||||||
return DeleteRequestResponseDto(
|
return DeleteRequestResponseDto(
|
||||||
id = request.id,
|
id = request.id,
|
||||||
status = DeleteRequestStatusDto.DELETED,
|
|
||||||
deletedAt = deletedAt.toOffsetDateTime(),
|
deletedAt = deletedAt.toOffsetDateTime(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -197,6 +198,21 @@ class RequestService(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun findRequests(query: RequestListFilter): Page<RequestEntity> =
|
||||||
|
requestRepository.findRequests(
|
||||||
|
includeDeleted = query.includeDeleted,
|
||||||
|
deletedStatus = RequestStatus.DELETED,
|
||||||
|
status = query.status?.toEntity(),
|
||||||
|
surveyType = query.surveyType?.toEntity(),
|
||||||
|
kpp = query.kpp,
|
||||||
|
highPriorityTransmit = query.highPriorityTransmit,
|
||||||
|
beginFrom = query.beginFrom?.toUtcLocalDateTime(),
|
||||||
|
beginTo = query.beginTo?.toUtcLocalDateTime(),
|
||||||
|
endFrom = query.endFrom?.toUtcLocalDateTime(),
|
||||||
|
endTo = query.endTo?.toUtcLocalDateTime(),
|
||||||
|
pageable = PageRequest.of(query.page, query.size, query.sort.toRequestSort()),
|
||||||
|
)
|
||||||
|
|
||||||
private fun RequestEntity.toResponse(): RequestResponseDto {
|
private fun RequestEntity.toResponse(): RequestResponseDto {
|
||||||
val optics = requestOpticsParamsRepository.findById(id).orElse(null)?.toDto()
|
val optics = requestOpticsParamsRepository.findById(id).orElse(null)?.toDto()
|
||||||
val rsa = requestRsaParamsRepository.findById(id).orElse(null)?.toDto()
|
val rsa = requestRsaParamsRepository.findById(id).orElse(null)?.toDto()
|
||||||
@@ -247,6 +263,25 @@ class RequestService(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun RequestEntity.toMapItemResponse(): RequestMapItemDto {
|
||||||
|
return RequestMapItemDto(
|
||||||
|
id = id,
|
||||||
|
name = name,
|
||||||
|
status = status.toDto(),
|
||||||
|
surveyType = surveyType.toDto(),
|
||||||
|
geometry = geometry,
|
||||||
|
importance = importance,
|
||||||
|
beginDateTime = beginDateTime.toOffsetDateTime(),
|
||||||
|
endDateTime = endDateTime.toOffsetDateTime(),
|
||||||
|
kpp = kpp,
|
||||||
|
highPriorityTransmit = highPriorityTransmit,
|
||||||
|
coveragePercent = coverage().currentPercent,
|
||||||
|
createdAt = createdAt.toOffsetDateTime(),
|
||||||
|
updatedAt = updatedAt.toOffsetDateTime(),
|
||||||
|
deletedAt = deletedAt?.toOffsetDateTime(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private fun RequestEntity.coverage(): CoverageStateDto {
|
private fun RequestEntity.coverage(): CoverageStateDto {
|
||||||
return CoverageStateDto(
|
return CoverageStateDto(
|
||||||
requiredPercent = coverageRequiredPercent,
|
requiredPercent = coverageRequiredPercent,
|
||||||
@@ -254,7 +289,7 @@ class RequestService(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun CreateRequestRequestDto.surveyType(): RequestSurveyType {
|
private fun CreateRequestDto.surveyType(): RequestSurveyType {
|
||||||
return when {
|
return when {
|
||||||
optics != null && rsa != null -> RequestSurveyType.COMBINED
|
optics != null && rsa != null -> RequestSurveyType.COMBINED
|
||||||
optics != null -> RequestSurveyType.OPTICS
|
optics != null -> RequestSurveyType.OPTICS
|
||||||
|
|||||||
+9
-9
@@ -133,8 +133,8 @@ class CellsControllerTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `get v1 cells with requests returns request fragments`() {
|
fun `get v1 cells priority map returns request fragments`() {
|
||||||
mockMvc.perform(get("/v1/cells/with-requests").accept(MediaType.APPLICATION_JSON))
|
mockMvc.perform(get("/v1/cells/priority-map").accept(MediaType.APPLICATION_JSON))
|
||||||
.andExpect(status().isOk)
|
.andExpect(status().isOk)
|
||||||
.andExpect(jsonPath("$.items").isArray)
|
.andExpect(jsonPath("$.items").isArray)
|
||||||
.andExpect(jsonPath("$.items[0].cellNum").value(42))
|
.andExpect(jsonPath("$.items[0].cellNum").value(42))
|
||||||
@@ -150,9 +150,9 @@ class CellsControllerTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `get v1 cells with requests rejects partial aggregation parameters`() {
|
fun `get v1 cells priority map rejects partial aggregation parameters`() {
|
||||||
mockMvc.perform(
|
mockMvc.perform(
|
||||||
get("/v1/cells/with-requests")
|
get("/v1/cells/priority-map")
|
||||||
.queryParam("countLat", "2")
|
.queryParam("countLat", "2")
|
||||||
.accept(MediaType.APPLICATION_JSON),
|
.accept(MediaType.APPLICATION_JSON),
|
||||||
)
|
)
|
||||||
@@ -162,9 +162,9 @@ class CellsControllerTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `get v1 cells with requests rejects invalid numeric parameters`() {
|
fun `get v1 cells priority map rejects invalid numeric parameters`() {
|
||||||
mockMvc.perform(
|
mockMvc.perform(
|
||||||
get("/v1/cells/with-requests")
|
get("/v1/cells/priority-map")
|
||||||
.queryParam("minImportance", "-1")
|
.queryParam("minImportance", "-1")
|
||||||
.accept(MediaType.APPLICATION_JSON),
|
.accept(MediaType.APPLICATION_JSON),
|
||||||
)
|
)
|
||||||
@@ -173,7 +173,7 @@ class CellsControllerTest {
|
|||||||
.andExpect(jsonPath("$.message").value("minImportance must be greater than or equal to 0"))
|
.andExpect(jsonPath("$.message").value("minImportance must be greater than or equal to 0"))
|
||||||
|
|
||||||
mockMvc.perform(
|
mockMvc.perform(
|
||||||
get("/v1/cells/with-requests")
|
get("/v1/cells/priority-map")
|
||||||
.queryParam("countLat", "0")
|
.queryParam("countLat", "0")
|
||||||
.queryParam("countLong", "1")
|
.queryParam("countLong", "1")
|
||||||
.accept(MediaType.APPLICATION_JSON),
|
.accept(MediaType.APPLICATION_JSON),
|
||||||
@@ -184,9 +184,9 @@ class CellsControllerTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `get v1 cells with requests accepts complete aggregation parameters`() {
|
fun `get v1 cells priority map accepts complete aggregation parameters`() {
|
||||||
mockMvc.perform(
|
mockMvc.perform(
|
||||||
get("/v1/cells/with-requests")
|
get("/v1/cells/priority-map")
|
||||||
.queryParam("countLat", "1")
|
.queryParam("countLat", "1")
|
||||||
.queryParam("countLong", "1")
|
.queryParam("countLong", "1")
|
||||||
.accept(MediaType.APPLICATION_JSON),
|
.accept(MediaType.APPLICATION_JSON),
|
||||||
|
|||||||
+34
-7
@@ -11,6 +11,7 @@ import org.mockito.ArgumentMatchers.isNull
|
|||||||
import org.mockito.Mockito.doAnswer
|
import org.mockito.Mockito.doAnswer
|
||||||
import org.mockito.Mockito.doReturn
|
import org.mockito.Mockito.doReturn
|
||||||
import org.mockito.Mockito.mock
|
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.EarthCellEntity
|
||||||
import org.nstart.dep265.requestservice.entity.RequestEntity
|
import org.nstart.dep265.requestservice.entity.RequestEntity
|
||||||
import org.nstart.dep265.requestservice.entity.RequestCellEntity
|
import org.nstart.dep265.requestservice.entity.RequestCellEntity
|
||||||
@@ -345,6 +346,32 @@ class RequestControllerOpenApiSkeletonTest {
|
|||||||
.andExpect(jsonPath("$.items[0].importance").value(10.0))
|
.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
|
@Test
|
||||||
fun `get v1 requests rejects unsupported sort field`() {
|
fun `get v1 requests rejects unsupported sort field`() {
|
||||||
mockMvc.perform(
|
mockMvc.perform(
|
||||||
@@ -370,7 +397,7 @@ class RequestControllerOpenApiSkeletonTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@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 id = UUID.fromString("3fa85f64-5717-4562-b3fc-2c963f66afa6")
|
||||||
val earthCell = EarthCellEntity(
|
val earthCell = EarthCellEntity(
|
||||||
cellId = 1,
|
cellId = 1,
|
||||||
@@ -397,7 +424,7 @@ class RequestControllerOpenApiSkeletonTest {
|
|||||||
.`when`(requestCellRepository)
|
.`when`(requestCellRepository)
|
||||||
.findWithCellByRequestId(id)
|
.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(status().isOk)
|
||||||
.andExpect(jsonPath("$.request.id").value(id.toString()))
|
.andExpect(jsonPath("$.request.id").value(id.toString()))
|
||||||
.andExpect(jsonPath("$.request.name").value("Тест1"))
|
.andExpect(jsonPath("$.request.name").value("Тест1"))
|
||||||
@@ -411,7 +438,7 @@ class RequestControllerOpenApiSkeletonTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@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")
|
val id = UUID.fromString("3fa85f64-5717-4562-b3fc-2c963f66afa6")
|
||||||
doReturn(Optional.of(existingRequest()))
|
doReturn(Optional.of(existingRequest()))
|
||||||
.`when`(requestRepository)
|
.`when`(requestRepository)
|
||||||
@@ -420,14 +447,14 @@ class RequestControllerOpenApiSkeletonTest {
|
|||||||
.`when`(requestCellRepository)
|
.`when`(requestCellRepository)
|
||||||
.findWithCellByRequestId(id)
|
.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(status().isOk)
|
||||||
.andExpect(jsonPath("$.request.id").value(id.toString()))
|
.andExpect(jsonPath("$.request.id").value(id.toString()))
|
||||||
.andExpect(jsonPath("$.cells").isEmpty)
|
.andExpect(jsonPath("$.cells").isEmpty)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@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 id = UUID.fromString("3fa85f64-5717-4562-b3fc-2c963f66afa6")
|
||||||
val request = existingRequest().also { existingRequest ->
|
val request = existingRequest().also { existingRequest ->
|
||||||
existingRequest.status = RequestStatus.DELETED
|
existingRequest.status = RequestStatus.DELETED
|
||||||
@@ -440,7 +467,7 @@ class RequestControllerOpenApiSkeletonTest {
|
|||||||
.`when`(requestCellRepository)
|
.`when`(requestCellRepository)
|
||||||
.findWithCellByRequestId(id)
|
.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(status().isOk)
|
||||||
.andExpect(jsonPath("$.request.status").value("DELETED"))
|
.andExpect(jsonPath("$.request.status").value("DELETED"))
|
||||||
.andExpect(jsonPath("$.request.deletedAt").exists())
|
.andExpect(jsonPath("$.request.deletedAt").exists())
|
||||||
@@ -454,7 +481,7 @@ class RequestControllerOpenApiSkeletonTest {
|
|||||||
mockMvc.perform(get("/v1/requests/$id").accept(MediaType.APPLICATION_JSON))
|
mockMvc.perform(get("/v1/requests/$id").accept(MediaType.APPLICATION_JSON))
|
||||||
.andExpect(status().isNotFound)
|
.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)
|
.andExpect(status().isNotFound)
|
||||||
|
|
||||||
mockMvc.perform(delete("/v1/requests/$id").accept(MediaType.APPLICATION_JSON))
|
mockMvc.perform(delete("/v1/requests/$id").accept(MediaType.APPLICATION_JSON))
|
||||||
|
|||||||
+3
-3
@@ -18,7 +18,7 @@ class RequestApiDtoContractTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `create request dto matches openapi input fields`() {
|
fun `create request dto matches openapi input fields`() {
|
||||||
val request = objectMapper.readValue<CreateRequestRequestDto>(
|
val request = objectMapper.readValue<CreateRequestDto>(
|
||||||
"""
|
"""
|
||||||
{
|
{
|
||||||
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
|
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
|
||||||
@@ -66,14 +66,14 @@ class RequestApiDtoContractTest {
|
|||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
|
|
||||||
assertFailsWith<Exception> {
|
assertFailsWith<Exception> {
|
||||||
objectMapper.readValue<CreateRequestRequestDto>(payloadWithSurveyType)
|
objectMapper.readValue<CreateRequestDto>(payloadWithSurveyType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `create request serialization does not expose survey type`() {
|
fun `create request serialization does not expose survey type`() {
|
||||||
val json = objectMapper.writeValueAsString(
|
val json = objectMapper.writeValueAsString(
|
||||||
CreateRequestRequestDto(
|
CreateRequestDto(
|
||||||
id = UUID.fromString("3fa85f64-5717-4562-b3fc-2c963f66afa6"),
|
id = UUID.fromString("3fa85f64-5717-4562-b3fc-2c963f66afa6"),
|
||||||
name = "Тест1",
|
name = "Тест1",
|
||||||
geometry = "POLYGON ((37.5 55.5, 37.7 55.5, 37.7 55.7, 37.5 55.7, 37.5 55.5))",
|
geometry = "POLYGON ((37.5 55.5, 37.7 55.5, 37.7 55.7, 37.5 55.7, 37.5 55.5))",
|
||||||
|
|||||||
+4
-4
@@ -212,7 +212,7 @@ class CellsQueryServiceJpaTest @Autowired constructor(
|
|||||||
)
|
)
|
||||||
entityManager.clear()
|
entityManager.clear()
|
||||||
|
|
||||||
val response = service.listCellsWithRequests(
|
val response = service.listCellsPriorityMap(
|
||||||
minImportance = null,
|
minImportance = null,
|
||||||
countLat = null,
|
countLat = null,
|
||||||
countLong = null,
|
countLong = null,
|
||||||
@@ -234,7 +234,7 @@ class CellsQueryServiceJpaTest @Autowired constructor(
|
|||||||
saveCell(cellNum = 11, importance = 2.0)
|
saveCell(cellNum = 11, importance = 2.0)
|
||||||
entityManager.clear()
|
entityManager.clear()
|
||||||
|
|
||||||
val response = service.listCellsWithRequests(
|
val response = service.listCellsPriorityMap(
|
||||||
minImportance = 2.0,
|
minImportance = 2.0,
|
||||||
countLat = null,
|
countLat = null,
|
||||||
countLong = null,
|
countLong = null,
|
||||||
@@ -249,7 +249,7 @@ class CellsQueryServiceJpaTest @Autowired constructor(
|
|||||||
saveCell(cellNum = 11, importance = 1.0)
|
saveCell(cellNum = 11, importance = 1.0)
|
||||||
entityManager.clear()
|
entityManager.clear()
|
||||||
|
|
||||||
val response = service.listCellsWithRequests(
|
val response = service.listCellsPriorityMap(
|
||||||
minImportance = 0.0,
|
minImportance = 0.0,
|
||||||
countLat = null,
|
countLat = null,
|
||||||
countLong = null,
|
countLong = null,
|
||||||
@@ -264,7 +264,7 @@ class CellsQueryServiceJpaTest @Autowired constructor(
|
|||||||
saveCell(cellNum = 11, importance = 0.002)
|
saveCell(cellNum = 11, importance = 0.002)
|
||||||
entityManager.clear()
|
entityManager.clear()
|
||||||
|
|
||||||
val response = service.listCellsWithRequests(
|
val response = service.listCellsPriorityMap(
|
||||||
minImportance = 0.001,
|
minImportance = 0.001,
|
||||||
countLat = null,
|
countLat = null,
|
||||||
countLong = null,
|
countLong = null,
|
||||||
|
|||||||
+5
-5
@@ -121,7 +121,7 @@ class CellsQueryServiceTest {
|
|||||||
}
|
}
|
||||||
val service = service(earthCellRepository)
|
val service = service(earthCellRepository)
|
||||||
|
|
||||||
val response = service.listCellsWithRequests(
|
val response = service.listCellsPriorityMap(
|
||||||
minImportance = null,
|
minImportance = null,
|
||||||
countLat = null,
|
countLat = null,
|
||||||
countLong = null,
|
countLong = null,
|
||||||
@@ -149,7 +149,7 @@ class CellsQueryServiceTest {
|
|||||||
}
|
}
|
||||||
val service = service(earthCellRepository)
|
val service = service(earthCellRepository)
|
||||||
|
|
||||||
val response = service.listCellsWithRequests(
|
val response = service.listCellsPriorityMap(
|
||||||
minImportance = 2.0,
|
minImportance = 2.0,
|
||||||
countLat = null,
|
countLat = null,
|
||||||
countLong = null,
|
countLong = null,
|
||||||
@@ -164,7 +164,7 @@ class CellsQueryServiceTest {
|
|||||||
val service = service(emptyCellsRepository())
|
val service = service(emptyCellsRepository())
|
||||||
|
|
||||||
assertThrows<InvalidCellsQueryException> {
|
assertThrows<InvalidCellsQueryException> {
|
||||||
service.listCellsWithRequests(
|
service.listCellsPriorityMap(
|
||||||
minImportance = null,
|
minImportance = null,
|
||||||
countLat = 2,
|
countLat = 2,
|
||||||
countLong = null,
|
countLong = null,
|
||||||
@@ -172,7 +172,7 @@ class CellsQueryServiceTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
assertThrows<InvalidCellsQueryException> {
|
assertThrows<InvalidCellsQueryException> {
|
||||||
service.listCellsWithRequests(
|
service.listCellsPriorityMap(
|
||||||
minImportance = null,
|
minImportance = null,
|
||||||
countLat = null,
|
countLat = null,
|
||||||
countLong = 2,
|
countLong = 2,
|
||||||
@@ -194,7 +194,7 @@ class CellsQueryServiceTest {
|
|||||||
}
|
}
|
||||||
val service = service(earthCellRepository)
|
val service = service(earthCellRepository)
|
||||||
|
|
||||||
val response = service.listCellsWithRequests(
|
val response = service.listCellsPriorityMap(
|
||||||
minImportance = null,
|
minImportance = null,
|
||||||
countLat = 1,
|
countLat = 1,
|
||||||
countLong = 2,
|
countLong = 2,
|
||||||
|
|||||||
+25
-12
@@ -2,7 +2,7 @@ package org.nstart.dep265.requestservice.service
|
|||||||
|
|
||||||
import jakarta.persistence.EntityManager
|
import jakarta.persistence.EntityManager
|
||||||
import org.junit.jupiter.api.Test
|
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.RequestStatusDto
|
||||||
import org.nstart.dep265.requestservice.dto.SurveyTypeDto
|
import org.nstart.dep265.requestservice.dto.SurveyTypeDto
|
||||||
import org.nstart.dep265.requestservice.PcpRequestServiceApplication
|
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")
|
val activeId = saveRequest(status = RequestStatus.ACTIVE, createdAt = "2026-01-02T00:00:00")
|
||||||
saveRequest(status = RequestStatus.DELETED, createdAt = "2026-01-03T00: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(listOf(activeId), response.items.map { request -> request.id })
|
||||||
assertEquals("Тест1", response.items.single().name)
|
assertEquals("Тест1", response.items.single().name)
|
||||||
@@ -65,12 +65,25 @@ class RequestServiceListRequestsJpaTest @Autowired constructor(
|
|||||||
assertEquals(1, response.totalPages)
|
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
|
@Test
|
||||||
fun `list requests includes deleted when includeDeleted is true`() {
|
fun `list requests includes deleted when includeDeleted is true`() {
|
||||||
val activeId = saveRequest(status = RequestStatus.ACTIVE, createdAt = "2026-01-02T00:00:00")
|
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 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(listOf(deletedId, activeId), response.items.map { request -> request.id })
|
||||||
assertEquals(2, response.totalItems)
|
assertEquals(2, response.totalItems)
|
||||||
@@ -81,7 +94,7 @@ class RequestServiceListRequestsJpaTest @Autowired constructor(
|
|||||||
val activeId = saveRequest(status = RequestStatus.ACTIVE)
|
val activeId = saveRequest(status = RequestStatus.ACTIVE)
|
||||||
saveRequest(status = RequestStatus.ACCEPTED)
|
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 })
|
assertEquals(listOf(activeId), response.items.map { request -> request.id })
|
||||||
}
|
}
|
||||||
@@ -91,7 +104,7 @@ class RequestServiceListRequestsJpaTest @Autowired constructor(
|
|||||||
val rsaId = saveRequest(surveyType = RequestSurveyType.RSA)
|
val rsaId = saveRequest(surveyType = RequestSurveyType.RSA)
|
||||||
saveRequest(surveyType = RequestSurveyType.OPTICS)
|
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 })
|
assertEquals(listOf(rsaId), response.items.map { request -> request.id })
|
||||||
}
|
}
|
||||||
@@ -101,7 +114,7 @@ class RequestServiceListRequestsJpaTest @Autowired constructor(
|
|||||||
val matchedId = saveRequest(kpp = mutableListOf(1, 2))
|
val matchedId = saveRequest(kpp = mutableListOf(1, 2))
|
||||||
saveRequest(kpp = mutableListOf(3, 4))
|
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 })
|
assertEquals(listOf(matchedId), response.items.map { request -> request.id })
|
||||||
}
|
}
|
||||||
@@ -111,7 +124,7 @@ class RequestServiceListRequestsJpaTest @Autowired constructor(
|
|||||||
val highPriorityId = saveRequest(highPriorityTransmit = true)
|
val highPriorityId = saveRequest(highPriorityTransmit = true)
|
||||||
saveRequest(highPriorityTransmit = false)
|
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 })
|
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")
|
saveRequest(beginDateTime = "2026-02-01T00:00:00", endDateTime = "2026-02-28T00:00:00")
|
||||||
|
|
||||||
val response = service.listRequests(
|
val response = service.listRequests(
|
||||||
ListRequestsQueryDto(
|
RequestListFilter(
|
||||||
beginFrom = OffsetDateTime.parse("2026-01-10T00:00:00Z"),
|
beginFrom = OffsetDateTime.parse("2026-01-10T00:00:00Z"),
|
||||||
beginTo = OffsetDateTime.parse("2026-01-31T23:59:59Z"),
|
beginTo = OffsetDateTime.parse("2026-01-31T23:59:59Z"),
|
||||||
)
|
)
|
||||||
@@ -139,7 +152,7 @@ class RequestServiceListRequestsJpaTest @Autowired constructor(
|
|||||||
saveRequest(endDateTime = "2026-02-01T00:00:00")
|
saveRequest(endDateTime = "2026-02-01T00:00:00")
|
||||||
|
|
||||||
val response = service.listRequests(
|
val response = service.listRequests(
|
||||||
ListRequestsQueryDto(
|
RequestListFilter(
|
||||||
endFrom = OffsetDateTime.parse("2026-01-10T00:00:00Z"),
|
endFrom = OffsetDateTime.parse("2026-01-10T00:00:00Z"),
|
||||||
endTo = OffsetDateTime.parse("2026-01-31T23:59:59Z"),
|
endTo = OffsetDateTime.parse("2026-01-31T23:59:59Z"),
|
||||||
)
|
)
|
||||||
@@ -154,7 +167,7 @@ class RequestServiceListRequestsJpaTest @Autowired constructor(
|
|||||||
saveRequest(createdAt = "2026-01-02T00:00:00")
|
saveRequest(createdAt = "2026-01-02T00:00:00")
|
||||||
val oldestId = saveRequest(createdAt = "2026-01-01T00: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(listOf(oldestId), response.items.map { request -> request.id })
|
||||||
assertEquals(1, response.page)
|
assertEquals(1, response.page)
|
||||||
@@ -169,7 +182,7 @@ class RequestServiceListRequestsJpaTest @Autowired constructor(
|
|||||||
val newestId = saveRequest(createdAt = "2026-01-03T00:00:00")
|
val newestId = saveRequest(createdAt = "2026-01-03T00:00:00")
|
||||||
val middleId = saveRequest(createdAt = "2026-01-02T00: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 })
|
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 latestBeginId = saveRequest(beginDateTime = "2026-01-03T00:00:00")
|
||||||
val earliestBeginId = saveRequest(beginDateTime = "2026-01-01T00: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 })
|
assertEquals(listOf(earliestBeginId, latestBeginId), response.items.map { request -> request.id })
|
||||||
}
|
}
|
||||||
|
|||||||
+31
-5
@@ -11,8 +11,8 @@ import org.mockito.Mockito.mock
|
|||||||
import org.mockito.Mockito.never
|
import org.mockito.Mockito.never
|
||||||
import org.mockito.Mockito.verify
|
import org.mockito.Mockito.verify
|
||||||
import org.mockito.Mockito.verifyNoInteractions
|
import org.mockito.Mockito.verifyNoInteractions
|
||||||
import org.nstart.dep265.requestservice.dto.CreateRequestRequestDto
|
import org.nstart.dep265.requestservice.dto.CreateRequestDto
|
||||||
import org.nstart.dep265.requestservice.dto.ListRequestsQueryDto
|
import org.nstart.dep265.requestservice.dto.RequestListFilter
|
||||||
import org.nstart.dep265.requestservice.dto.OpticsParamsDto
|
import org.nstart.dep265.requestservice.dto.OpticsParamsDto
|
||||||
import org.nstart.dep265.requestservice.dto.OpticsResultTypeDto
|
import org.nstart.dep265.requestservice.dto.OpticsResultTypeDto
|
||||||
import org.nstart.dep265.requestservice.entity.EarthCellEntity
|
import org.nstart.dep265.requestservice.entity.EarthCellEntity
|
||||||
@@ -215,12 +215,38 @@ class RequestServiceTest {
|
|||||||
pageableMatcher(),
|
pageableMatcher(),
|
||||||
)
|
)
|
||||||
|
|
||||||
val response = service.listRequests(ListRequestsQueryDto())
|
val response = service.listRequests(RequestListFilter())
|
||||||
|
|
||||||
assertEquals(REQUEST_NAME, response.items.single().name)
|
assertEquals(REQUEST_NAME, response.items.single().name)
|
||||||
assertEquals(REQUEST_IMPORTANCE, response.items.single().importance)
|
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
|
@Test
|
||||||
fun `create request rejects duplicate id without touching existing request state`() {
|
fun `create request rejects duplicate id without touching existing request state`() {
|
||||||
doReturn(true)
|
doReturn(true)
|
||||||
@@ -254,8 +280,8 @@ class RequestServiceTest {
|
|||||||
verify(requestCellRepository).deleteByRequestId(REQUEST_ID)
|
verify(requestCellRepository).deleteByRequestId(REQUEST_ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createRequestDto(): CreateRequestRequestDto {
|
private fun createRequestDto(): CreateRequestDto {
|
||||||
return CreateRequestRequestDto(
|
return CreateRequestDto(
|
||||||
id = REQUEST_ID,
|
id = REQUEST_ID,
|
||||||
name = REQUEST_NAME,
|
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))",
|
geometry = "POLYGON ((37.5 55.5, 37.7 55.5, 37.7 55.7, 37.5 55.7, 37.5 55.5))",
|
||||||
|
|||||||
+1
-1
@@ -52,7 +52,7 @@ class EarthService(
|
|||||||
fun reqcells(id : String): RequestWithCellsDTO? =
|
fun reqcells(id : String): RequestWithCellsDTO? =
|
||||||
webClientBuilder.build()
|
webClientBuilder.build()
|
||||||
.get()
|
.get()
|
||||||
.uri("$url/v1/requests/$id/with-cells")
|
.uri("$url/v1/requests/$id/cells")
|
||||||
.retrieve()
|
.retrieve()
|
||||||
.bodyToMono(RequestWithCellsResponseDto::class.java)
|
.bodyToMono(RequestWithCellsResponseDto::class.java)
|
||||||
.block()
|
.block()
|
||||||
|
|||||||
+2
-2
@@ -38,7 +38,7 @@ class CoverageSchemeServiceTest {
|
|||||||
val timeStop = LocalDateTime.of(2026, 4, 14, 12, 0)
|
val timeStop = LocalDateTime.of(2026, 4, 14, 12, 0)
|
||||||
val serverUrl = startServer(
|
val serverUrl = startServer(
|
||||||
mapOf(
|
mapOf(
|
||||||
"/v1/requests/req-1/with-cells" to stringHandler(200, requestWithCellsJson()),
|
"/v1/requests/req-1/cells" to stringHandler(200, requestWithCellsJson()),
|
||||||
"/api/coverage-schemes/calculate" to jsonHandler(
|
"/api/coverage-schemes/calculate" to jsonHandler(
|
||||||
CoverageSchemeResponseDTO(
|
CoverageSchemeResponseDTO(
|
||||||
targetPolygonWkt = "POLYGON ((30 10, 40 40, 20 40, 30 10))",
|
targetPolygonWkt = "POLYGON ((30 10, 40 40, 20 40, 30 10))",
|
||||||
@@ -111,7 +111,7 @@ class CoverageSchemeServiceTest {
|
|||||||
fun `requestCoverageScheme converts backend error to CustomErrorException`() {
|
fun `requestCoverageScheme converts backend error to CustomErrorException`() {
|
||||||
val serverUrl = startServer(
|
val serverUrl = startServer(
|
||||||
mapOf(
|
mapOf(
|
||||||
"/v1/requests/req-1/with-cells" to stringHandler(200, requestWithCellsJson()),
|
"/v1/requests/req-1/cells" to stringHandler(200, requestWithCellsJson()),
|
||||||
"/api/coverage-schemes/calculate" to stringHandler(400, """{"message":"coverage failed"}""")
|
"/api/coverage-schemes/calculate" to stringHandler(400, """{"message":"coverage failed"}""")
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|||||||
+1
-1
@@ -377,7 +377,7 @@ class EarthServiceTest {
|
|||||||
|
|
||||||
service.reqcells(requestId.toString())
|
service.reqcells(requestId.toString())
|
||||||
|
|
||||||
assertEquals("/v1/requests/$requestId/with-cells", requestedUris.single().path)
|
assertEquals("/v1/requests/$requestId/cells", requestedUris.single().path)
|
||||||
assertFalse(requestedUris.any { uri -> uri.path.startsWith("/api/") })
|
assertFalse(requestedUris.any { uri -> uri.path.startsWith("/api/") })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -49,7 +49,7 @@ class EarthService(
|
|||||||
fun reqcells(id : String): RequestWithCellsDTO? =
|
fun reqcells(id : String): RequestWithCellsDTO? =
|
||||||
webClientBuilder.build()
|
webClientBuilder.build()
|
||||||
.get()
|
.get()
|
||||||
.uri("$url/v1/requests/$id/with-cells")
|
.uri("$url/v1/requests/$id/cells")
|
||||||
.retrieve()
|
.retrieve()
|
||||||
.bodyToMono(RequestWithCellsResponseDto::class.java)
|
.bodyToMono(RequestWithCellsResponseDto::class.java)
|
||||||
.block()
|
.block()
|
||||||
|
|||||||
+1
-1
@@ -115,7 +115,7 @@ class EarthServiceTest {
|
|||||||
|
|
||||||
val response = service.reqcells(requestId.toString())!!
|
val response = service.reqcells(requestId.toString())!!
|
||||||
|
|
||||||
assertEquals("/v1/requests/$requestId/with-cells", requestedUris.single().path)
|
assertEquals("/v1/requests/$requestId/cells", requestedUris.single().path)
|
||||||
assertFalse(requestedUris.any { uri -> uri.path.contains("/api/requests/by-number") })
|
assertFalse(requestedUris.any { uri -> uri.path.contains("/api/requests/by-number") })
|
||||||
assertEquals(requestId, response.request.requestId)
|
assertEquals(requestId, response.request.requestId)
|
||||||
assertEquals("Request with cells", response.request.name)
|
assertEquals("Request with cells", response.request.name)
|
||||||
|
|||||||
Reference in New Issue
Block a user