mirror of
https://github.com/valitydev/claim-management-api.git
synced 2024-11-06 01:05:18 +00:00
Merge pull request #2 from rbkmoney/ft/JD-267/move-from-dark-api
Ft/jd 267/move from dark api
This commit is contained in:
commit
240b2bc5b1
15
pom.xml
15
pom.xml
@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>com.rbkmoney</groupId>
|
||||
<artifactId>service-parent-pom</artifactId>
|
||||
<version>1.2.2</version>
|
||||
<version>1.2.4</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>claim-management-api</artifactId>
|
||||
@ -26,10 +26,11 @@
|
||||
<exposed.ports>${server.port} ${management.port}</exposed.ports>
|
||||
<dockerfile.registry>${env.REGISTRY}</dockerfile.registry>
|
||||
|
||||
<swag-claim-management.version>1.29-d665bf2-server</swag-claim-management.version>
|
||||
<swag-claim-management.version>1.30-eafa8b6-server</swag-claim-management.version>
|
||||
<keycloak-spring-security.version>12.0.1</keycloak-spring-security.version>
|
||||
<bouncycastle-jdk15on.version>1.68</bouncycastle-jdk15on.version>
|
||||
<spring-cloud-contract-wiremock.version>2.2.4.RELEASE</spring-cloud-contract-wiremock.version>
|
||||
<spring-security.version>5.4.6</spring-security.version>
|
||||
<jjwt.version>0.9.1</jjwt.version>
|
||||
<kotlin-logging.version>2.0.6</kotlin-logging.version>
|
||||
<mockito-kotlin.version>3.2.0</mockito-kotlin.version>
|
||||
@ -115,6 +116,16 @@
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-config</artifactId>
|
||||
<version>${spring-security.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-web</artifactId>
|
||||
<version>${spring-security.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
|
@ -17,12 +17,7 @@ import com.rbkmoney.damsel.claim_management.InvalidClaimStatus
|
||||
import com.rbkmoney.damsel.claim_management.LimitExceeded
|
||||
import com.rbkmoney.swag.claim_management.api.ProcessingApi
|
||||
import com.rbkmoney.swag.claim_management.model.Claim
|
||||
import com.rbkmoney.swag.claim_management.model.GeneralError
|
||||
import com.rbkmoney.swag.claim_management.model.InlineResponse200
|
||||
import com.rbkmoney.swag.claim_management.model.InlineResponse400
|
||||
import com.rbkmoney.swag.claim_management.model.InlineResponse4001
|
||||
import com.rbkmoney.swag.claim_management.model.InlineResponse4002
|
||||
import com.rbkmoney.swag.claim_management.model.InlineResponse4003
|
||||
import com.rbkmoney.swag.claim_management.model.Modification
|
||||
import mu.KotlinLogging
|
||||
import org.apache.thrift.TException
|
||||
@ -53,54 +48,31 @@ class ClaimManagementController(
|
||||
@NotNull @Size(min = 1, max = 40) xRequestId: String?,
|
||||
@NotNull @Valid changeset: List<Modification>?,
|
||||
@Size(min = 1, max = 40) xRequestDeadline: String?
|
||||
): ResponseEntity<Claim> {
|
||||
return try {
|
||||
): ResponseEntity<Claim> =
|
||||
performRequest("createClaim", xRequestId!!) {
|
||||
log.info { "Process 'createClaim' get started, xRequestId=$xRequestId" }
|
||||
partyManagementService.checkStatus(xRequestId)
|
||||
deadlineChecker.checkDeadline(xRequestDeadline, xRequestId)
|
||||
val claim = claimManagementService.createClaim(keycloakService.partyId, changeset!!)
|
||||
log.info { "Claim created, xRequestId=$xRequestId, claimId=${claim.id}" }
|
||||
ResponseEntity.ok(claim)
|
||||
} catch (ex: DeadlineException) {
|
||||
val msg = ex.message
|
||||
val response: InlineResponse4001 = InlineResponse4001()
|
||||
.code(InlineResponse4001.CodeEnum.INVALIDDEADLINE)
|
||||
.message(msg)
|
||||
throw BadRequestException(msg, ex, response)
|
||||
} catch (ex: InvalidChangeset) {
|
||||
val msg = "Invalid changeset, xRequestId=$xRequestId, reason='${ex.reason}'"
|
||||
val response: InlineResponse4001 = InlineResponse4001()
|
||||
.code(InlineResponse4001.CodeEnum.INVALIDCHANGESET)
|
||||
.message(msg)
|
||||
throw BadRequestException(msg, ex, response)
|
||||
} catch (ex: TException) {
|
||||
throw buildDarkApi5xxException("createClaim", xRequestId, ex)
|
||||
}
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAuthority('party:read')")
|
||||
override fun getClaimByID(
|
||||
@NotNull @Size(min = 1, max = 40) xRequestId: String?,
|
||||
@NotNull @Valid claimId: Long?,
|
||||
@Size(min = 1, max = 40) xRequestDeadline: String?
|
||||
): ResponseEntity<Claim> {
|
||||
return try {
|
||||
): ResponseEntity<Claim> =
|
||||
performRequest("getClaimByID", xRequestId!!, claimId!!) {
|
||||
log.info { "Process 'getClaimByID' get started, xRequestId=$xRequestId, claimId=$claimId" }
|
||||
partyManagementService.checkStatus(xRequestId)
|
||||
deadlineChecker.checkDeadline(xRequestDeadline, xRequestId)
|
||||
val claim = claimManagementService.getClaimById(keycloakService.partyId, claimId!!)
|
||||
val claim = claimManagementService.getClaimById(keycloakService.partyId, claimId)
|
||||
log.info { "Got a claim, xRequestId=$xRequestId, claimId=$claimId" }
|
||||
|
||||
ResponseEntity.ok(claim)
|
||||
} catch (ex: DeadlineException) {
|
||||
val msg = ex.message
|
||||
val response: GeneralError = GeneralError().message(msg)
|
||||
throw BadRequestException(msg, ex, response)
|
||||
} catch (ex: ClaimNotFound) {
|
||||
throw buildNotFoundException(xRequestId!!, claimId!!, ex)
|
||||
} catch (ex: TException) {
|
||||
throw buildDarkApi5xxException("getClaimByID", xRequestId, ex)
|
||||
}
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAuthority('party:write')")
|
||||
override fun revokeClaimByID(
|
||||
@ -109,38 +81,16 @@ class ClaimManagementController(
|
||||
@NotNull @Valid claimRevision: Int?,
|
||||
@Size(min = 1, max = 40) xRequestDeadline: String?,
|
||||
@Valid reason: String?
|
||||
): ResponseEntity<Void> {
|
||||
return try {
|
||||
): ResponseEntity<Void> =
|
||||
performRequest("revokeClaimByID", xRequestId!!, claimId!!, claimRevision!!) {
|
||||
log.info { "Process 'revokeClaimByID' get started, xRequestId=$xRequestId, claimId=$claimId" }
|
||||
partyManagementService.checkStatus(xRequestId)
|
||||
deadlineChecker.checkDeadline(xRequestDeadline, xRequestId)
|
||||
claimManagementService.revokeClaimById(keycloakService.partyId, claimId!!, claimRevision!!, reason)
|
||||
claimManagementService.revokeClaimById(keycloakService.partyId, claimId, claimRevision, reason)
|
||||
log.info { "Successful revoke claim, xRequestId=$xRequestId, claimId=$claimId" }
|
||||
|
||||
ResponseEntity<Void>(HttpStatus.OK)
|
||||
} catch (ex: DeadlineException) {
|
||||
val msg = ex.message
|
||||
val response: InlineResponse4002 = InlineResponse4002()
|
||||
.code(InlineResponse4002.CodeEnum.INVALIDDEADLINE)
|
||||
.message(msg)
|
||||
throw BadRequestException(msg, ex, response)
|
||||
} catch (ex: InvalidClaimStatus) {
|
||||
val msg = "Invalid claim status, xRequestId=$xRequestId, status=${ex.status}"
|
||||
val response: InlineResponse4002 = InlineResponse4002()
|
||||
.code(InlineResponse4002.CodeEnum.INVALIDCLAIMSTATUS)
|
||||
.message(msg)
|
||||
throw BadRequestException(msg, ex, response)
|
||||
} catch (ex: InvalidClaimRevision) {
|
||||
val msg = "Invalid claim revision, xRequestId=$xRequestId, claimRevision=$claimRevision"
|
||||
val response: InlineResponse4002 = InlineResponse4002()
|
||||
.code(InlineResponse4002.CodeEnum.INVALIDCLAIMREVISION)
|
||||
.message(msg)
|
||||
throw BadRequestException(msg, ex, response)
|
||||
} catch (ex: ClaimNotFound) {
|
||||
throw buildNotFoundException(xRequestId!!, claimId!!, ex)
|
||||
} catch (ex: TException) {
|
||||
throw buildDarkApi5xxException("revokeClaimByID", xRequestId, ex)
|
||||
}
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAuthority('party:write')")
|
||||
override fun requestReviewClaimByID(
|
||||
@ -148,38 +98,16 @@ class ClaimManagementController(
|
||||
@NotNull @Valid claimId: Long?,
|
||||
@NotNull @Valid claimRevision: Int?,
|
||||
@Size(min = 1, max = 40) xRequestDeadline: String?
|
||||
): ResponseEntity<Void> {
|
||||
return try {
|
||||
): ResponseEntity<Void> =
|
||||
performRequest("requestClaimReviewById", xRequestId!!, claimId!!, claimRevision!!) {
|
||||
log.info { "Process 'requestReviewClaimByID' get started, xRequestId=$xRequestId, claimId=$claimId" }
|
||||
partyManagementService.checkStatus(xRequestId)
|
||||
deadlineChecker.checkDeadline(xRequestDeadline, xRequestId)
|
||||
claimManagementService.requestClaimReviewById(keycloakService.partyId, claimId!!, claimRevision!!)
|
||||
claimManagementService.requestClaimReviewById(keycloakService.partyId, claimId, claimRevision)
|
||||
log.info { "Successful request claim review, xRequestId=$xRequestId, claimId=$claimId" }
|
||||
|
||||
ResponseEntity<Void>(HttpStatus.OK)
|
||||
} catch (ex: DeadlineException) {
|
||||
val msg = ex.message
|
||||
val response: InlineResponse4002 = InlineResponse4002()
|
||||
.code(InlineResponse4002.CodeEnum.INVALIDDEADLINE)
|
||||
.message(msg)
|
||||
throw BadRequestException(msg, ex, response)
|
||||
} catch (ex: InvalidClaimStatus) {
|
||||
val msg = "Invalid claim status, xRequestId=$xRequestId, status=${ex.status}"
|
||||
val response: InlineResponse4002 = InlineResponse4002()
|
||||
.code(InlineResponse4002.CodeEnum.INVALIDCLAIMSTATUS)
|
||||
.message(msg)
|
||||
throw BadRequestException(msg, ex, response)
|
||||
} catch (ex: InvalidClaimRevision) {
|
||||
val msg = "Invalid claim revision, xRequestId=$xRequestId, claimRevision=$claimRevision"
|
||||
val response: InlineResponse4002 = InlineResponse4002()
|
||||
.code(InlineResponse4002.CodeEnum.INVALIDCLAIMREVISION)
|
||||
.message(msg)
|
||||
throw BadRequestException(msg, ex, response)
|
||||
} catch (ex: ClaimNotFound) {
|
||||
throw buildNotFoundException(xRequestId!!, claimId!!, ex)
|
||||
} catch (ex: TException) {
|
||||
throw buildDarkApi5xxException("requestClaimReviewById", xRequestId, ex)
|
||||
}
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAuthority('party:read')")
|
||||
override fun searchClaims(
|
||||
@ -189,12 +117,12 @@ class ClaimManagementController(
|
||||
@Size(min = 1, max = 40) continuationToken: String?,
|
||||
@Valid claimId: Long?,
|
||||
@Valid claimStatuses: List<String>?
|
||||
): ResponseEntity<InlineResponse200> {
|
||||
return try {
|
||||
): ResponseEntity<InlineResponse200> =
|
||||
performRequest("searchClaims", xRequestId!!, claimId!!) {
|
||||
log.info { "Process 'searchClaims' get started, xRequestId=$xRequestId, claimId=$claimId" }
|
||||
partyManagementService.checkStatus(xRequestId)
|
||||
deadlineChecker.checkDeadline(xRequestDeadline, xRequestId)
|
||||
val response: InlineResponse200 = claimManagementService.searchClaims(
|
||||
val response = claimManagementService.searchClaims(
|
||||
keycloakService.partyId,
|
||||
limit!!,
|
||||
continuationToken,
|
||||
@ -205,96 +133,75 @@ class ClaimManagementController(
|
||||
"For status list, xRequestId=$xRequestId, claimId=$claimId, list statuses=$claimStatuses, " +
|
||||
"size results=${response.result.size}"
|
||||
}
|
||||
|
||||
ResponseEntity.ok(response)
|
||||
} catch (ex: DeadlineException) {
|
||||
val msg = ex.message
|
||||
val response: InlineResponse400 = InlineResponse400()
|
||||
.code(InlineResponse400.CodeEnum.INVALIDDEADLINE)
|
||||
.message(msg)
|
||||
throw BadRequestException(msg, ex, response)
|
||||
} catch (ex: LimitExceeded) {
|
||||
val msg = "Limit exceeded, xRequestId=$xRequestId"
|
||||
val response: InlineResponse400 = InlineResponse400()
|
||||
.code(InlineResponse400.CodeEnum.LIMITEXCEEDED)
|
||||
.message(msg)
|
||||
throw BadRequestException(msg, ex, response)
|
||||
} catch (ex: BadContinuationToken) {
|
||||
val msg = "Bad continuation token, xRequestId=$xRequestId, reason=${ex.reason}"
|
||||
val response: InlineResponse400 = InlineResponse400()
|
||||
.code(InlineResponse400.CodeEnum.BADCONTINUATIONTOKEN)
|
||||
.message(msg)
|
||||
throw BadRequestException(msg, ex, response)
|
||||
} catch (ex: TException) {
|
||||
throw buildDarkApi5xxException("searchClaims", xRequestId, ex)
|
||||
}
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAuthority('party:write')")
|
||||
override fun updateClaimByID(
|
||||
@NotNull @Size(min = 1, max = 40) xRequestId: String?,
|
||||
@NotNull @Valid claimId: Long,
|
||||
@NotNull @Valid claimId: Long?,
|
||||
@NotNull @Valid claimRevision: Int?,
|
||||
@NotNull @Valid changeset: List<Modification>?,
|
||||
@Size(min = 1, max = 40) xRequestDeadline: String?
|
||||
): ResponseEntity<Void> {
|
||||
return try {
|
||||
): ResponseEntity<Void> =
|
||||
performRequest("updateClaimByID", xRequestId!!, claimId!!, claimRevision!!) {
|
||||
log.info { "Process 'updateClaimByID' get started, requestId=$xRequestId, claimId=$claimId" }
|
||||
partyManagementService.checkStatus(xRequestId)
|
||||
deadlineChecker.checkDeadline(xRequestDeadline, xRequestId)
|
||||
claimManagementService.updateClaimById(keycloakService.partyId, claimId, claimRevision!!, changeset!!)
|
||||
claimManagementService.updateClaimById(keycloakService.partyId, claimId, claimRevision, changeset!!)
|
||||
log.info { "Successful update claim, xRequestId=$xRequestId, claimId=$claimId" }
|
||||
|
||||
ResponseEntity<Void>(HttpStatus.OK)
|
||||
}
|
||||
|
||||
private fun <T> performRequest(
|
||||
methodName: String,
|
||||
xRequestId: String,
|
||||
claimId: Long? = null,
|
||||
claimRevision: Int? = null,
|
||||
operation: () -> ResponseEntity<T>
|
||||
): ResponseEntity<T> =
|
||||
try {
|
||||
operation.invoke()
|
||||
} catch (ex: DeadlineException) {
|
||||
val msg = ex.message
|
||||
val response: InlineResponse4003 = InlineResponse4003()
|
||||
.code(InlineResponse4003.CodeEnum.INVALIDDEADLINE)
|
||||
.message(msg)
|
||||
val response = ErrorData(ErrorData.Code.INVALIDDEADLINE, msg)
|
||||
throw BadRequestException(msg, ex, response)
|
||||
} catch (ex: InvalidClaimStatus) {
|
||||
val msg = "Invalid claim status, xRequestId=$xRequestId, status=${ex.status}"
|
||||
val response: InlineResponse4003 = InlineResponse4003()
|
||||
.code(InlineResponse4003.CodeEnum.INVALIDCLAIMSTATUS)
|
||||
.message(msg)
|
||||
val response = ErrorData(ErrorData.Code.INVALIDCLAIMSTATUS, msg)
|
||||
throw BadRequestException(msg, ex, response)
|
||||
} catch (ex: InvalidClaimRevision) {
|
||||
val msg = "Invalid claim revision, xRequestId=$xRequestId, claimRevision=$claimRevision"
|
||||
val response: InlineResponse4003 = InlineResponse4003()
|
||||
.code(InlineResponse4003.CodeEnum.INVALIDCLAIMREVISION)
|
||||
.message(msg)
|
||||
val response = ErrorData(ErrorData.Code.INVALIDCLAIMREVISION, msg)
|
||||
throw BadRequestException(msg, ex, response)
|
||||
} catch (ex: ChangesetConflict) {
|
||||
val msg = "Changeset conflict, xRequestId=$xRequestId, conflictedId=${ex.conflictedId}"
|
||||
val response: InlineResponse4003 = InlineResponse4003()
|
||||
.code(InlineResponse4003.CodeEnum.CHANGESETCONFLICT)
|
||||
.message(msg)
|
||||
val response = ErrorData(ErrorData.Code.CHANGESETCONFLICT, msg)
|
||||
throw BadRequestException(msg, ex, response)
|
||||
} catch (ex: InvalidChangeset) {
|
||||
val msg = "Invalid changeset, xRequestId=$xRequestId, reason='${ex.reason}'"
|
||||
val response: InlineResponse4003 = InlineResponse4003()
|
||||
.code(InlineResponse4003.CodeEnum.INVALIDCHANGESET)
|
||||
.message(msg)
|
||||
val response = ErrorData(ErrorData.Code.INVALIDCHANGESET, msg)
|
||||
throw BadRequestException(msg, ex, response)
|
||||
} catch (ex: LimitExceeded) {
|
||||
val msg = "Limit exceeded, xRequestId=$xRequestId"
|
||||
val response = ErrorData(ErrorData.Code.LIMITEXCEEDED, msg)
|
||||
throw BadRequestException(msg, ex, response)
|
||||
} catch (ex: BadContinuationToken) {
|
||||
val msg = "Bad continuation token, xRequestId=$xRequestId, reason=${ex.reason}"
|
||||
val response = ErrorData(ErrorData.Code.BADCONTINUATIONTOKEN, msg)
|
||||
throw BadRequestException(msg, ex, response)
|
||||
} catch (ex: ClaimNotFound) {
|
||||
throw buildNotFoundException(xRequestId!!, claimId, ex)
|
||||
val msg = "Claim not found, claimId=$claimId, xRequestId=$xRequestId"
|
||||
val response = ErrorData(message = msg)
|
||||
throw NotFoundException(msg, ex, response)
|
||||
} catch (ex: TException) {
|
||||
throw buildDarkApi5xxException("updateClaimByID", xRequestId, ex)
|
||||
throw DarkApi5xxException(
|
||||
"Some TException while requesting api='$API_NAME', method='$methodName', xRequestId=$xRequestId",
|
||||
ex
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildNotFoundException(xRequestId: String, claimId: Long, ex: ClaimNotFound): NotFoundException {
|
||||
val msg = "Claim not found, claimId=$claimId, xRequestId=$xRequestId"
|
||||
val response = GeneralError().message(msg)
|
||||
return NotFoundException(msg, ex, response)
|
||||
}
|
||||
|
||||
private fun buildDarkApi5xxException(
|
||||
methodName: String?,
|
||||
xRequestId: String?,
|
||||
ex: TException?
|
||||
) = DarkApi5xxException(
|
||||
"Some TException while requesting api='$API_NAME', method='$methodName', xRequestId=$xRequestId",
|
||||
ex
|
||||
)
|
||||
|
||||
companion object {
|
||||
const val API_NAME = "claim-management"
|
||||
|
@ -0,0 +1,127 @@
|
||||
package com.rbkmoney.claimmanagementapi.controller
|
||||
|
||||
import com.rbkmoney.claimmanagementapi.exception.client.BadRequestException
|
||||
import com.rbkmoney.claimmanagementapi.exception.client.DarkApi4xxException
|
||||
import com.rbkmoney.claimmanagementapi.exception.client.ForbiddenException
|
||||
import com.rbkmoney.claimmanagementapi.exception.client.NotFoundException
|
||||
import com.rbkmoney.claimmanagementapi.exception.server.DarkApi5xxException
|
||||
import mu.KotlinLogging
|
||||
import org.springframework.http.HttpHeaders
|
||||
import org.springframework.http.HttpStatus
|
||||
import org.springframework.http.ResponseEntity
|
||||
import org.springframework.security.access.AccessDeniedException
|
||||
import org.springframework.web.HttpMediaTypeNotAcceptableException
|
||||
import org.springframework.web.HttpMediaTypeNotSupportedException
|
||||
import org.springframework.web.bind.MethodArgumentNotValidException
|
||||
import org.springframework.web.bind.MissingServletRequestParameterException
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler
|
||||
import org.springframework.web.bind.annotation.ResponseStatus
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice
|
||||
import org.springframework.web.client.HttpClientErrorException
|
||||
import org.springframework.web.context.request.WebRequest
|
||||
import java.lang.Exception
|
||||
import java.net.http.HttpTimeoutException
|
||||
|
||||
@RestControllerAdvice
|
||||
class ErrorControllerAdvice {
|
||||
|
||||
private val log = KotlinLogging.logger { }
|
||||
|
||||
// ----------------- 4xx -----------------------------------------------------
|
||||
@ExceptionHandler(BadRequestException::class)
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
fun handleBadRequestException(e: BadRequestException): Any {
|
||||
log.warn(e) { "<- Res [400]: Not valid" }
|
||||
return e.response
|
||||
}
|
||||
|
||||
@ExceptionHandler(MethodArgumentNotValidException::class)
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
fun handleMethodArgumentNotValidException(e: MethodArgumentNotValidException) {
|
||||
log.warn(e) { "<- Res [400]: MethodArgument not valid" }
|
||||
}
|
||||
|
||||
@ExceptionHandler(MissingServletRequestParameterException::class)
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
fun handleMissingServletRequestParameterException(e: MissingServletRequestParameterException) {
|
||||
log.warn(e) { "<- Res [400]: Missing ServletRequestParameter" }
|
||||
}
|
||||
|
||||
@ExceptionHandler(AccessDeniedException::class)
|
||||
@ResponseStatus(HttpStatus.FORBIDDEN)
|
||||
fun handleAccessDeniedException(e: AccessDeniedException) {
|
||||
log.warn(e) { "<- Res [403]: Request denied access" }
|
||||
}
|
||||
|
||||
@ExceptionHandler(ForbiddenException::class)
|
||||
@ResponseStatus(HttpStatus.FORBIDDEN)
|
||||
fun handleForbiddenException(e: ForbiddenException) {
|
||||
log.warn(e) { "<- Res [403]: Request denied access" }
|
||||
}
|
||||
|
||||
@ExceptionHandler(NotFoundException::class)
|
||||
@ResponseStatus(HttpStatus.NOT_FOUND)
|
||||
fun handleFileNotFoundException(e: NotFoundException): Any {
|
||||
log.warn(e) { "<- Res [404]: Not found" }
|
||||
return e.response
|
||||
}
|
||||
|
||||
@ExceptionHandler(HttpMediaTypeNotAcceptableException::class)
|
||||
@ResponseStatus(HttpStatus.NOT_ACCEPTABLE)
|
||||
fun handleHttpMediaTypeNotAcceptable(e: HttpMediaTypeNotAcceptableException) {
|
||||
log.warn(e) { "<- Res [406]: MediaType not acceptable" }
|
||||
}
|
||||
|
||||
@ExceptionHandler(HttpMediaTypeNotSupportedException::class)
|
||||
fun handleHttpMediaTypeNotSupported(
|
||||
e: HttpMediaTypeNotSupportedException,
|
||||
request: WebRequest
|
||||
): ResponseEntity<*> {
|
||||
log.warn(e) { "<- Res [415]: MediaType not supported" }
|
||||
return ResponseEntity.status(HttpStatus.UNSUPPORTED_MEDIA_TYPE)
|
||||
.headers(httpHeaders(e))
|
||||
.build<Any>()
|
||||
}
|
||||
|
||||
@ExceptionHandler(DarkApi4xxException::class)
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
fun handleDarkApiClientException(e: DarkApi4xxException) {
|
||||
log.warn(e) { "<- Res [400]: Unrecognized Error by controller" }
|
||||
}
|
||||
|
||||
// ----------------- 5xx -----------------------------------------------------
|
||||
@ExceptionHandler(HttpClientErrorException::class)
|
||||
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
fun handleHttpClientErrorException(e: HttpClientErrorException) {
|
||||
log.error(e) {
|
||||
"<- Res [500]: Error with using inner http client, code=${e.statusCode}, body=${e.responseBodyAsString}"
|
||||
}
|
||||
}
|
||||
|
||||
@ExceptionHandler(HttpTimeoutException::class)
|
||||
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
fun handleHttpTimeoutException(e: HttpTimeoutException) {
|
||||
log.error(e) { "<- Res [500]: Timeout with using inner http client" }
|
||||
}
|
||||
|
||||
@ExceptionHandler(DarkApi5xxException::class)
|
||||
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
fun handleHttpTimeoutException(e: DarkApi5xxException) {
|
||||
log.error(e) { "<- Res [500]: Unrecognized inner error" }
|
||||
}
|
||||
|
||||
@ExceptionHandler(Exception::class)
|
||||
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
fun handleException(e: Exception) {
|
||||
log.error(e) { "<- Res [500]: Unrecognized inner error" }
|
||||
}
|
||||
|
||||
private fun httpHeaders(e: HttpMediaTypeNotSupportedException): HttpHeaders {
|
||||
val headers = HttpHeaders()
|
||||
val mediaTypes = e.supportedMediaTypes
|
||||
if (mediaTypes.isNotEmpty()) {
|
||||
headers.accept = mediaTypes
|
||||
}
|
||||
return headers
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package com.rbkmoney.claimmanagementapi.controller
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.fasterxml.jackson.annotation.JsonValue
|
||||
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
data class ErrorData(
|
||||
@field:JsonProperty("code")
|
||||
val code: Code? = null,
|
||||
@field:JsonProperty("message")
|
||||
val message: String? = null
|
||||
) {
|
||||
enum class Code(private val value: String) {
|
||||
INVALIDCLAIMSTATUS("invalidClaimStatus"),
|
||||
CHANGESETCONFLICT("changesetConflict"),
|
||||
INVALIDCHANGESET("invalidChangeset"),
|
||||
INVALIDCLAIMREVISION("invalidClaimRevision"),
|
||||
LIMITEXCEEDED("limitExceeded"),
|
||||
BADCONTINUATIONTOKEN("badContinuationToken"),
|
||||
INVALIDDEADLINE("invalidDeadline");
|
||||
|
||||
@JsonValue
|
||||
override fun toString() = value
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package com.rbkmoney.claimmanagementapi.converter.claim
|
||||
|
||||
import com.rbkmoney.claimmanagementapi.converter.DarkApiConverter
|
||||
import org.springframework.stereotype.Component
|
||||
import com.rbkmoney.damsel.claim_management.ExternalInfoModificationUnit as ThriftExternalInfoModificationUnit
|
||||
import com.rbkmoney.swag.claim_management.model.ClaimModificationType as SwagClaimModificationType
|
||||
import com.rbkmoney.swag.claim_management.model.ExternalInfoModificationUnit as SwagExternalInfoModificationUnit
|
||||
|
||||
@Component
|
||||
class ClaimExternalInfoModificationUnitConverter :
|
||||
DarkApiConverter<ThriftExternalInfoModificationUnit, SwagExternalInfoModificationUnit> {
|
||||
|
||||
override fun convertToThrift(value: SwagExternalInfoModificationUnit) =
|
||||
ThriftExternalInfoModificationUnit().apply {
|
||||
documentId = value.documentId
|
||||
roistatId = value.roistatId
|
||||
}
|
||||
|
||||
override fun convertToSwag(value: ThriftExternalInfoModificationUnit) =
|
||||
SwagExternalInfoModificationUnit().apply {
|
||||
documentId = value.documentId
|
||||
roistatId = value.roistatId
|
||||
claimModificationType = SwagClaimModificationType.ClaimModificationTypeEnum.EXTERNALINFOMODIFICATIONUNIT
|
||||
}
|
||||
}
|
@ -8,6 +8,7 @@ import com.rbkmoney.damsel.claim_management.Modification as ThriftModification
|
||||
import com.rbkmoney.swag.claim_management.model.ClaimModification as SwagClaimModification
|
||||
import com.rbkmoney.swag.claim_management.model.CommentModificationUnit as SwagCommentModificationUnit
|
||||
import com.rbkmoney.swag.claim_management.model.DocumentModificationUnit as SwagDocumentModificationUnit
|
||||
import com.rbkmoney.swag.claim_management.model.ExternalInfoModificationUnit as SwagExternalInfoModificationUnit
|
||||
import com.rbkmoney.swag.claim_management.model.FileModificationUnit as SwagFileModificationUnit
|
||||
import com.rbkmoney.swag.claim_management.model.Modification as SwagModification
|
||||
import com.rbkmoney.swag.claim_management.model.StatusModificationUnit as SwagStatusModificationUnit
|
||||
@ -17,7 +18,8 @@ class ClaimModificationConverter(
|
||||
private val documentModificationUnitConverter: ClaimDocumentModificationUnitConverter,
|
||||
private val commentModificationUnitConverter: ClaimCommentModificationUnitConverter,
|
||||
private val statusModificationUnitConverter: ClaimStatusModificationUnitConverter,
|
||||
private val fileModificationUnitConverter: ClaimFileModificationUnitConverter
|
||||
private val fileModificationUnitConverter: ClaimFileModificationUnitConverter,
|
||||
private val extInfoModificationUnitConverter: ClaimExternalInfoModificationUnitConverter
|
||||
) : DarkApiConverter<ThriftModification, SwagClaimModification> {
|
||||
|
||||
override fun convertToThrift(value: SwagClaimModification): ThriftModification {
|
||||
@ -44,6 +46,11 @@ class ClaimModificationConverter(
|
||||
val fileModificationUnit = swagClaimModificationType as SwagFileModificationUnit
|
||||
claimModification.fileModification = fileModificationUnitConverter.convertToThrift(fileModificationUnit)
|
||||
}
|
||||
ClaimModificationTypeEnum.EXTERNALINFOMODIFICATIONUNIT -> {
|
||||
val extInfoModificationUnit = swagClaimModificationType as SwagExternalInfoModificationUnit
|
||||
claimModification.externalInfoModification =
|
||||
extInfoModificationUnitConverter.convertToThrift(extInfoModificationUnit)
|
||||
}
|
||||
else -> throw IllegalArgumentException("Unknown claim modification type: $swagClaimModificationType")
|
||||
}
|
||||
modification.claimModification = claimModification
|
||||
@ -74,6 +81,11 @@ class ClaimModificationConverter(
|
||||
swagClaimModification.claimModificationType =
|
||||
fileModificationUnitConverter.convertToSwag(fileModificationUnit)
|
||||
}
|
||||
claimModification.isSetExternalInfoModification -> {
|
||||
val externalInfoModificationUnit = claimModification.externalInfoModification
|
||||
swagClaimModification.claimModificationType =
|
||||
extInfoModificationUnitConverter.convertToSwag(externalInfoModificationUnit)
|
||||
}
|
||||
else -> throw IllegalArgumentException("Unknown claim modification type")
|
||||
}
|
||||
swagClaimModification.modificationType = SwagModification.ModificationTypeEnum.CLAIMMODIFICATION
|
||||
|
@ -0,0 +1,173 @@
|
||||
package com.rbkmoney.claimmanagementapi.controller
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import com.rbkmoney.claimmanagementapi.config.AbstractKeycloakOpenIdAsWiremockConfig
|
||||
import com.rbkmoney.claimmanagementapi.service.ClaimManagementService
|
||||
import com.rbkmoney.claimmanagementapi.service.ClaimManagementServiceTest
|
||||
import com.rbkmoney.claimmanagementapi.service.PartyManagementService
|
||||
import com.rbkmoney.damsel.claim_management.ChangesetConflict
|
||||
import com.rbkmoney.damsel.claim_management.ClaimNotFound
|
||||
import com.rbkmoney.damsel.claim_management.InvalidChangeset
|
||||
import com.rbkmoney.damsel.claim_management.InvalidClaimRevision
|
||||
import com.rbkmoney.damsel.claim_management.InvalidClaimStatus
|
||||
import org.apache.thrift.TException
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.mockito.ArgumentMatchers
|
||||
import org.mockito.kotlin.doAnswer
|
||||
import org.mockito.kotlin.doNothing
|
||||
import org.mockito.kotlin.reset
|
||||
import org.mockito.kotlin.whenever
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.boot.test.mock.mockito.MockBean
|
||||
import org.springframework.http.MediaType
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultMatchers
|
||||
import java.time.Instant
|
||||
import java.time.temporal.ChronoUnit
|
||||
import java.util.UUID
|
||||
|
||||
class ErrorControllerTest : AbstractKeycloakOpenIdAsWiremockConfig() {
|
||||
|
||||
@Autowired
|
||||
private lateinit var mockMvc: MockMvc
|
||||
|
||||
@Autowired
|
||||
private lateinit var objectMapper: ObjectMapper
|
||||
|
||||
@MockBean
|
||||
private lateinit var partyManagementService: PartyManagementService
|
||||
|
||||
@MockBean
|
||||
private lateinit var claimManagementService: ClaimManagementService
|
||||
|
||||
@BeforeEach
|
||||
fun setUp() {
|
||||
doNothing().whenever(partyManagementService).checkStatus(ArgumentMatchers.anyString())
|
||||
doNothing().whenever(partyManagementService).checkStatus()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testThenClaimManagementClientThrowingExceptions() {
|
||||
whenever(claimManagementService.getClaimById(ArgumentMatchers.anyString(), ArgumentMatchers.anyLong()))
|
||||
.doAnswer { throw ClaimNotFound() }
|
||||
mockMvc.perform(
|
||||
MockMvcRequestBuilders.get("/processing/claims/{claimID}", ArgumentMatchers.anyLong())
|
||||
.contentType(MediaType.APPLICATION_JSON_UTF8)
|
||||
.header("Authorization", "Bearer " + generateReadJwt())
|
||||
.header("X-Request-ID", string())
|
||||
.header("X-Request-Deadline", Instant.now().plus(1, ChronoUnit.DAYS).toString())
|
||||
).andExpect(MockMvcResultMatchers.status().isNotFound)
|
||||
reset(claimManagementService)
|
||||
whenever(
|
||||
claimManagementService.updateClaimById(
|
||||
ArgumentMatchers.anyString(),
|
||||
ArgumentMatchers.anyLong(),
|
||||
ArgumentMatchers.anyInt(),
|
||||
ArgumentMatchers.anyList()
|
||||
)
|
||||
).doAnswer { throw ClaimNotFound() }
|
||||
mockMvc.perform(
|
||||
MockMvcRequestBuilders.put("/processing/claims/{claimID}/update", ArgumentMatchers.anyLong())
|
||||
.contentType(MediaType.APPLICATION_JSON_UTF8)
|
||||
.header("Authorization", "Bearer " + generateWriteJwt())
|
||||
.header("X-Request-ID", string())
|
||||
.header("X-Request-Deadline", Instant.now().plus(1, ChronoUnit.DAYS).toString())
|
||||
.param("claimRevision", 123.toString())
|
||||
.content(objectMapper.writeValueAsBytes(ClaimManagementServiceTest.modifications))
|
||||
).andExpect(MockMvcResultMatchers.status().isNotFound)
|
||||
reset(claimManagementService)
|
||||
whenever(
|
||||
claimManagementService.updateClaimById(
|
||||
ArgumentMatchers.anyString(),
|
||||
ArgumentMatchers.anyLong(),
|
||||
ArgumentMatchers.anyInt(),
|
||||
ArgumentMatchers.anyList()
|
||||
)
|
||||
).doAnswer { throw InvalidClaimStatus() }
|
||||
mockMvc.perform(
|
||||
MockMvcRequestBuilders.put("/processing/claims/{claimID}/update", ArgumentMatchers.anyLong())
|
||||
.contentType(MediaType.APPLICATION_JSON_UTF8)
|
||||
.header("Authorization", "Bearer " + generateWriteJwt())
|
||||
.header("X-Request-ID", string())
|
||||
.header("X-Request-Deadline", Instant.now().plus(1, ChronoUnit.DAYS).toString())
|
||||
.param("claimRevision", 123.toString())
|
||||
.content(objectMapper.writeValueAsBytes(ClaimManagementServiceTest.modifications))
|
||||
).andExpect(MockMvcResultMatchers.status().isBadRequest)
|
||||
reset(claimManagementService)
|
||||
whenever(
|
||||
claimManagementService.updateClaimById(
|
||||
ArgumentMatchers.anyString(),
|
||||
ArgumentMatchers.anyLong(),
|
||||
ArgumentMatchers.anyInt(),
|
||||
ArgumentMatchers.anyList()
|
||||
)
|
||||
).doAnswer { throw InvalidClaimRevision() }
|
||||
mockMvc.perform(
|
||||
MockMvcRequestBuilders.put("/processing/claims/{claimID}/update", ArgumentMatchers.anyLong())
|
||||
.contentType(MediaType.APPLICATION_JSON_UTF8)
|
||||
.header("Authorization", "Bearer " + generateWriteJwt())
|
||||
.header("X-Request-ID", string())
|
||||
.header("X-Request-Deadline", Instant.now().plus(1, ChronoUnit.DAYS).toString())
|
||||
.param("claimRevision", 123.toString())
|
||||
.content(objectMapper.writeValueAsBytes(ClaimManagementServiceTest.modifications))
|
||||
).andExpect(MockMvcResultMatchers.status().isBadRequest)
|
||||
reset(claimManagementService)
|
||||
whenever(
|
||||
claimManagementService.updateClaimById(
|
||||
ArgumentMatchers.anyString(),
|
||||
ArgumentMatchers.anyLong(),
|
||||
ArgumentMatchers.anyInt(),
|
||||
ArgumentMatchers.anyList()
|
||||
)
|
||||
).doAnswer { throw ChangesetConflict() }
|
||||
mockMvc.perform(
|
||||
MockMvcRequestBuilders.put("/processing/claims/{claimID}/update", ArgumentMatchers.anyLong())
|
||||
.contentType(MediaType.APPLICATION_JSON_UTF8)
|
||||
.header("Authorization", "Bearer " + generateWriteJwt())
|
||||
.header("X-Request-ID", string())
|
||||
.header("X-Request-Deadline", Instant.now().plus(1, ChronoUnit.DAYS).toString())
|
||||
.param("claimRevision", 123.toString())
|
||||
.content(objectMapper.writeValueAsBytes(ClaimManagementServiceTest.modifications))
|
||||
).andExpect(MockMvcResultMatchers.status().isBadRequest)
|
||||
reset(claimManagementService)
|
||||
whenever(
|
||||
claimManagementService.updateClaimById(
|
||||
ArgumentMatchers.anyString(),
|
||||
ArgumentMatchers.anyLong(),
|
||||
ArgumentMatchers.anyInt(),
|
||||
ArgumentMatchers.anyList()
|
||||
)
|
||||
).doAnswer { throw InvalidChangeset() }
|
||||
mockMvc.perform(
|
||||
MockMvcRequestBuilders.put("/processing/claims/{claimID}/update", ArgumentMatchers.anyLong())
|
||||
.contentType(MediaType.APPLICATION_JSON_UTF8)
|
||||
.header("Authorization", "Bearer " + generateWriteJwt())
|
||||
.header("X-Request-ID", string())
|
||||
.header("X-Request-Deadline", Instant.now().plus(1, ChronoUnit.DAYS).toString())
|
||||
.param("claimRevision", 123.toString())
|
||||
.content(objectMapper.writeValueAsBytes(ClaimManagementServiceTest.modifications))
|
||||
).andExpect(MockMvcResultMatchers.status().isBadRequest)
|
||||
reset(claimManagementService)
|
||||
whenever(
|
||||
claimManagementService.updateClaimById(
|
||||
ArgumentMatchers.anyString(),
|
||||
ArgumentMatchers.anyLong(),
|
||||
ArgumentMatchers.anyInt(),
|
||||
ArgumentMatchers.anyList()
|
||||
)
|
||||
).doAnswer { throw TException() }
|
||||
mockMvc.perform(
|
||||
MockMvcRequestBuilders.put("/processing/claims/{claimID}/update", ArgumentMatchers.anyLong())
|
||||
.contentType(MediaType.APPLICATION_JSON_UTF8)
|
||||
.header("Authorization", "Bearer " + generateWriteJwt())
|
||||
.header("X-Request-ID", string())
|
||||
.header("X-Request-Deadline", Instant.now().plus(1, ChronoUnit.DAYS).toString())
|
||||
.param("claimRevision", 123.toString())
|
||||
.content(objectMapper.writeValueAsBytes(ClaimManagementServiceTest.modifications))
|
||||
).andExpect(MockMvcResultMatchers.status().isInternalServerError)
|
||||
}
|
||||
|
||||
private fun string() = UUID.randomUUID().toString()
|
||||
}
|
@ -156,7 +156,8 @@ class ClaimConvertersTest {
|
||||
ClaimDocumentModificationUnitConverter(),
|
||||
ClaimCommentModificationUnitConverter(),
|
||||
ClaimStatusModificationUnitConverter(ClaimStatusModificationConverter()),
|
||||
ClaimFileModificationUnitConverter()
|
||||
ClaimFileModificationUnitConverter(),
|
||||
ClaimExternalInfoModificationUnitConverter()
|
||||
)
|
||||
val swagStatusModUnit = SwagStatusModificationUnit().apply {
|
||||
claimModificationType = ClaimModificationTypeEnum.STATUSMODIFICATIONUNIT
|
||||
|
@ -133,7 +133,7 @@ class ClaimManagementServiceTest {
|
||||
return changeset
|
||||
}
|
||||
|
||||
private val modifications: List<SwagModification>
|
||||
val modifications: List<SwagModification>
|
||||
get() {
|
||||
val documentModification = DocumentModification()
|
||||
.apply { documentModificationType = DocumentModificationTypeEnum.DOCUMENTCREATED }
|
||||
|
Loading…
Reference in New Issue
Block a user