From f918acc01dfedc7a64aba658b8556acf852a18d7 Mon Sep 17 00:00:00 2001 From: vityaman Date: Tue, 30 Apr 2024 11:05:05 +0300 Subject: [PATCH 01/12] #91 Fixed 500 on PATCH /promotion/id --- .../app/spring/api/http/endpoint/PromotionHttpApi.kt | 6 +++--- .../spring/api/http/error/InvalidPromotionRequestStatus.kt | 4 ---- 2 files changed, 3 insertions(+), 7 deletions(-) delete mode 100644 botalka/src/main/kotlin/ru/vityaman/lms/botalka/app/spring/api/http/error/InvalidPromotionRequestStatus.kt diff --git a/botalka/src/main/kotlin/ru/vityaman/lms/botalka/app/spring/api/http/endpoint/PromotionHttpApi.kt b/botalka/src/main/kotlin/ru/vityaman/lms/botalka/app/spring/api/http/endpoint/PromotionHttpApi.kt index b007c3f..bd732c2 100644 --- a/botalka/src/main/kotlin/ru/vityaman/lms/botalka/app/spring/api/http/endpoint/PromotionHttpApi.kt +++ b/botalka/src/main/kotlin/ru/vityaman/lms/botalka/app/spring/api/http/endpoint/PromotionHttpApi.kt @@ -4,13 +4,13 @@ import org.springframework.beans.factory.annotation.Autowired import org.springframework.http.HttpStatus import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.RestController -import ru.vityaman.lms.botalka.app.spring.api.http.error.InvalidPromotionRequestStatus import ru.vityaman.lms.botalka.app.spring.api.http.message.toMessage import ru.vityaman.lms.botalka.app.spring.api.http.message.toModel import ru.vityaman.lms.botalka.app.spring.api.http.server.PromotionRequestDraftMessage import ru.vityaman.lms.botalka.app.spring.api.http.server.PromotionRequestMessage import ru.vityaman.lms.botalka.app.spring.api.http.server.PromotionRequestPatchMessage import ru.vityaman.lms.botalka.app.spring.api.http.server.apis.PromotionApi +import ru.vityaman.lms.botalka.core.exception.InvalidValueException import ru.vityaman.lms.botalka.core.logic.PromotionService import ru.vityaman.lms.botalka.core.model.PromotionRequest import ru.vityaman.lms.botalka.core.model.User @@ -27,9 +27,9 @@ class PromotionHttpApi( when (val status = promotionRequestPatchMessage.status.toModel()) { PromotionRequest.Status.CREATED -> { - throw InvalidPromotionRequestStatus( + throw InvalidValueException( buildString { - append("Can't change promotion request status") + append("Can't change promotion request status ") append("to ${status.toMessage()}") }, ) diff --git a/botalka/src/main/kotlin/ru/vityaman/lms/botalka/app/spring/api/http/error/InvalidPromotionRequestStatus.kt b/botalka/src/main/kotlin/ru/vityaman/lms/botalka/app/spring/api/http/error/InvalidPromotionRequestStatus.kt deleted file mode 100644 index 357e5eb..0000000 --- a/botalka/src/main/kotlin/ru/vityaman/lms/botalka/app/spring/api/http/error/InvalidPromotionRequestStatus.kt +++ /dev/null @@ -1,4 +0,0 @@ -package ru.vityaman.lms.botalka.app.spring.api.http.error - -class InvalidPromotionRequestStatus(message: String) : - Exception("Invalid promotion request status: $message") From c9de90b05e0faaa86c76b275498b82ca39fc7c0a Mon Sep 17 00:00:00 2001 From: vityaman Date: Tue, 30 Apr 2024 11:13:47 +0300 Subject: [PATCH 02/12] #91 Fixed 500 on POST /homework --- .../kotlin/ru/vityaman/lms/botalka/core/model/Homework.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/botalka/src/main/kotlin/ru/vityaman/lms/botalka/core/model/Homework.kt b/botalka/src/main/kotlin/ru/vityaman/lms/botalka/core/model/Homework.kt index 979d267..0799c5b 100644 --- a/botalka/src/main/kotlin/ru/vityaman/lms/botalka/core/model/Homework.kt +++ b/botalka/src/main/kotlin/ru/vityaman/lms/botalka/core/model/Homework.kt @@ -70,6 +70,10 @@ data class Homework( val deadlineMoment: OffsetDateTime, ) { init { + val maxDeadline = OffsetDateTime.parse("4096-08-08T08:08:08+03:00") + expect(deadlineMoment.isBefore(maxDeadline)) { + append("Homework deadline must be before $maxDeadline") + } expect(publicationMoment.plusMinutes(1).isBefore(deadlineMoment)) { append("Homework must be published 1 minute before deadline") } From acd75c16579953d6ca0a521d47c0a42c9813801a Mon Sep 17 00:00:00 2001 From: vityaman Date: Tue, 30 Apr 2024 11:56:07 +0300 Subject: [PATCH 03/12] #91 Catching invalid timestamp at json --- .../api/http/error/DriverExceptionMapping.kt | 17 +++++++++++++++++ botalka/src/main/resources/application.yml | 2 +- docker-compose.yml | 4 ++++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/botalka/src/main/kotlin/ru/vityaman/lms/botalka/app/spring/api/http/error/DriverExceptionMapping.kt b/botalka/src/main/kotlin/ru/vityaman/lms/botalka/app/spring/api/http/error/DriverExceptionMapping.kt index c6b4dee..495e5bb 100644 --- a/botalka/src/main/kotlin/ru/vityaman/lms/botalka/app/spring/api/http/error/DriverExceptionMapping.kt +++ b/botalka/src/main/kotlin/ru/vityaman/lms/botalka/app/spring/api/http/error/DriverExceptionMapping.kt @@ -1,6 +1,7 @@ package ru.vityaman.lms.botalka.app.spring.api.http.error import com.fasterxml.jackson.core.JsonParseException +import com.fasterxml.jackson.databind.JsonMappingException import org.springframework.http.HttpStatus import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.ExceptionHandler @@ -23,4 +24,20 @@ class DriverExceptionMapping { ), ) } + + @ExceptionHandler(JsonMappingException::class) + fun handle(exception: JsonMappingException): ResponseEntity { + val code = HttpStatus.BAD_REQUEST + val offset = exception.location.offsetDescription() + val message = exception.cause!!.message + return ResponseEntity + .status(code) + .body( + GeneralErrorMessage( + code = code.value(), + status = code.reasonPhrase, + message = "Json syntax error at $offset: $message", + ), + ) + } } diff --git a/botalka/src/main/resources/application.yml b/botalka/src/main/resources/application.yml index 8ef88f6..15a9a65 100644 --- a/botalka/src/main/resources/application.yml +++ b/botalka/src/main/resources/application.yml @@ -24,7 +24,7 @@ logging: root: INFO r2dbc: INFO sql: INFO - web: INFO + web: DEBUG group: r2dbc: org.springframework.r2dbc,org.springframework.data.r2dbc management: diff --git a/docker-compose.yml b/docker-compose.yml index 0053fdd..b52d819 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -44,6 +44,8 @@ services: - GF_SECURITY_ADMIN_PASSWORD=0000 networks: - lms-network + profiles: + - infra prometheus: container_name: lms-prometheus image: prom/prometheus @@ -53,6 +55,8 @@ services: - ./infra/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml networks: - lms-network + profiles: + - infra restler: container_name: lms-restler image: restler From cbfe02d6c8ae71b0e824cf72cf0d58e9be090fbb Mon Sep 17 00:00:00 2001 From: vityaman Date: Tue, 30 Apr 2024 11:58:02 +0300 Subject: [PATCH 04/12] #91 Fixed Undocumented HTTP status code --- botalka/src/main/resources/static/openapi/api.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/botalka/src/main/resources/static/openapi/api.yml b/botalka/src/main/resources/static/openapi/api.yml index 50f3cd8..403d287 100644 --- a/botalka/src/main/resources/static/openapi/api.yml +++ b/botalka/src/main/resources/static/openapi/api.yml @@ -69,6 +69,12 @@ paths: type: array items: $ref: '#/components/schemas/WorkspaceEvent' + 400: + description: Invalid parameters + content: + application/json: + schema: + $ref: '#/components/schemas/GeneralError' 404: description: Homework or student with given id not found content: From 7553ef059544a46f33d3eecce88408d73fee8357 Mon Sep 17 00:00:00 2001 From: vityaman Date: Tue, 30 Apr 2024 12:21:08 +0300 Subject: [PATCH 05/12] #91 Fixed Response violates schema with code 400 --- .../api/http/error/DriverExceptionMapping.kt | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/botalka/src/main/kotlin/ru/vityaman/lms/botalka/app/spring/api/http/error/DriverExceptionMapping.kt b/botalka/src/main/kotlin/ru/vityaman/lms/botalka/app/spring/api/http/error/DriverExceptionMapping.kt index 495e5bb..28709b5 100644 --- a/botalka/src/main/kotlin/ru/vityaman/lms/botalka/app/spring/api/http/error/DriverExceptionMapping.kt +++ b/botalka/src/main/kotlin/ru/vityaman/lms/botalka/app/spring/api/http/error/DriverExceptionMapping.kt @@ -2,6 +2,7 @@ package ru.vityaman.lms.botalka.app.spring.api.http.error import com.fasterxml.jackson.core.JsonParseException import com.fasterxml.jackson.databind.JsonMappingException +import com.fasterxml.jackson.databind.exc.MismatchedInputException import org.springframework.http.HttpStatus import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.ExceptionHandler @@ -25,18 +26,37 @@ class DriverExceptionMapping { ) } + @ExceptionHandler(MismatchedInputException::class) + fun handle(exception: MismatchedInputException): ResponseEntity { + val code = HttpStatus.BAD_REQUEST + val offset = exception.location.offsetDescription() + val message = buildString { + append("Json mismatched input error at $offset, ") + append("ensure that all required fields are set") + } + return ResponseEntity + .status(code) + .body( + GeneralErrorMessage( + code = code.value(), + status = code.reasonPhrase, + message = message, + ), + ) + } + @ExceptionHandler(JsonMappingException::class) fun handle(exception: JsonMappingException): ResponseEntity { val code = HttpStatus.BAD_REQUEST val offset = exception.location.offsetDescription() - val message = exception.cause!!.message + val cause = exception.cause?.message ?: "unknown cause" return ResponseEntity .status(code) .body( GeneralErrorMessage( code = code.value(), status = code.reasonPhrase, - message = "Json syntax error at $offset: $message", + message = "Json mapping error at $offset: $cause", ), ) } From b1ca49bd5a155c25c889d6ca6a60c934f14e0d38 Mon Sep 17 00:00:00 2001 From: vityaman Date: Tue, 30 Apr 2024 12:22:12 +0300 Subject: [PATCH 06/12] #91 Fixed Undocumented HTTP status code 400 --- botalka/src/main/resources/static/openapi/api.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/botalka/src/main/resources/static/openapi/api.yml b/botalka/src/main/resources/static/openapi/api.yml index 403d287..7b29d37 100644 --- a/botalka/src/main/resources/static/openapi/api.yml +++ b/botalka/src/main/resources/static/openapi/api.yml @@ -166,6 +166,12 @@ paths: application/json: schema: $ref: '#/components/schemas/User' + 400: + description: Invalid parameters + content: + application/json: + schema: + $ref: '#/components/schemas/GeneralError' 404: description: Not found content: From 1fb646b8a13cea36f6daf74a8df80ee45fab6192 Mon Sep 17 00:00:00 2001 From: vityaman Date: Tue, 30 Apr 2024 12:23:15 +0300 Subject: [PATCH 07/12] #91 Fixed Undocumented HTTP status code 400 --- botalka/src/main/resources/static/openapi/api.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/botalka/src/main/resources/static/openapi/api.yml b/botalka/src/main/resources/static/openapi/api.yml index 7b29d37..e49cbb8 100644 --- a/botalka/src/main/resources/static/openapi/api.yml +++ b/botalka/src/main/resources/static/openapi/api.yml @@ -230,6 +230,12 @@ paths: application/json: schema: $ref: '#/components/schemas/PromotionRequest' + 400: + description: Invalid parameters + content: + application/json: + schema: + $ref: '#/components/schemas/GeneralError' 404: description: User not found content: From 285a0b79531f9f06befccd2462a98f5d71d447a9 Mon Sep 17 00:00:00 2001 From: vityaman Date: Tue, 30 Apr 2024 12:31:44 +0300 Subject: [PATCH 08/12] #91 Fixed Undocumented HTTP status code 400 --- botalka/src/main/resources/static/openapi/api.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/botalka/src/main/resources/static/openapi/api.yml b/botalka/src/main/resources/static/openapi/api.yml index e49cbb8..711fb23 100644 --- a/botalka/src/main/resources/static/openapi/api.yml +++ b/botalka/src/main/resources/static/openapi/api.yml @@ -271,6 +271,12 @@ paths: responses: 204: description: Promotion request resolved + 400: + description: Invalid parameters + content: + application/json: + schema: + $ref: '#/components/schemas/GeneralError' 404: description: Promotion request not found content: From c9ea84b506a2652d5ffd78d495d87e7ad1dcb4a7 Mon Sep 17 00:00:00 2001 From: vityaman Date: Tue, 30 Apr 2024 12:47:21 +0300 Subject: [PATCH 09/12] #91 Fixed exception handling --- .../api/http/error/DriverExceptionMapping.kt | 26 +++++++++---------- botalka/src/main/resources/application.yml | 2 +- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/botalka/src/main/kotlin/ru/vityaman/lms/botalka/app/spring/api/http/error/DriverExceptionMapping.kt b/botalka/src/main/kotlin/ru/vityaman/lms/botalka/app/spring/api/http/error/DriverExceptionMapping.kt index 28709b5..32d6f69 100644 --- a/botalka/src/main/kotlin/ru/vityaman/lms/botalka/app/spring/api/http/error/DriverExceptionMapping.kt +++ b/botalka/src/main/kotlin/ru/vityaman/lms/botalka/app/spring/api/http/error/DriverExceptionMapping.kt @@ -26,37 +26,37 @@ class DriverExceptionMapping { ) } - @ExceptionHandler(MismatchedInputException::class) - fun handle(exception: MismatchedInputException): ResponseEntity { + @ExceptionHandler(JsonMappingException::class) + fun handle(exception: JsonMappingException): ResponseEntity { val code = HttpStatus.BAD_REQUEST - val offset = exception.location.offsetDescription() - val message = buildString { - append("Json mismatched input error at $offset, ") - append("ensure that all required fields are set") - } + val offset = exception.location?.offsetDescription() ?: "(?, ?)" + val cause = exception.cause?.message ?: "unknown cause" return ResponseEntity .status(code) .body( GeneralErrorMessage( code = code.value(), status = code.reasonPhrase, - message = message, + message = "Json mapping error at $offset: $cause", ), ) } - @ExceptionHandler(JsonMappingException::class) - fun handle(exception: JsonMappingException): ResponseEntity { + @ExceptionHandler(MismatchedInputException::class) + fun handle(exception: MismatchedInputException): ResponseEntity { val code = HttpStatus.BAD_REQUEST - val offset = exception.location.offsetDescription() - val cause = exception.cause?.message ?: "unknown cause" + val offset = exception.location?.offsetDescription() ?: "(?, ?)" + val message = buildString { + append("Json mismatched input error at $offset, ") + append("ensure that all required fields are set") + } return ResponseEntity .status(code) .body( GeneralErrorMessage( code = code.value(), status = code.reasonPhrase, - message = "Json mapping error at $offset: $cause", + message = message, ), ) } diff --git a/botalka/src/main/resources/application.yml b/botalka/src/main/resources/application.yml index 15a9a65..8ef88f6 100644 --- a/botalka/src/main/resources/application.yml +++ b/botalka/src/main/resources/application.yml @@ -24,7 +24,7 @@ logging: root: INFO r2dbc: INFO sql: INFO - web: DEBUG + web: INFO group: r2dbc: org.springframework.r2dbc,org.springframework.data.r2dbc management: From dbe4239218bf12fe6cda21b153c552fd45cea294 Mon Sep 17 00:00:00 2001 From: vityaman Date: Tue, 30 Apr 2024 12:50:40 +0300 Subject: [PATCH 10/12] #91 Fixed homework score range --- .../main/kotlin/ru/vityaman/lms/botalka/core/model/Homework.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/botalka/src/main/kotlin/ru/vityaman/lms/botalka/core/model/Homework.kt b/botalka/src/main/kotlin/ru/vityaman/lms/botalka/core/model/Homework.kt index 0799c5b..bdf7334 100644 --- a/botalka/src/main/kotlin/ru/vityaman/lms/botalka/core/model/Homework.kt +++ b/botalka/src/main/kotlin/ru/vityaman/lms/botalka/core/model/Homework.kt @@ -58,7 +58,7 @@ data class Homework( } companion object { - private val range = 0..2000 + private val range = 1..2000 } } From 8f0f4c8f1378b35bbd12cfcd62b4fceaf24c9fd7 Mon Sep 17 00:00:00 2001 From: vityaman Date: Tue, 30 Apr 2024 13:14:32 +0300 Subject: [PATCH 11/12] #91 Fixed invalid json input output --- .../api/http/error/DriverExceptionMapping.kt | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/botalka/src/main/kotlin/ru/vityaman/lms/botalka/app/spring/api/http/error/DriverExceptionMapping.kt b/botalka/src/main/kotlin/ru/vityaman/lms/botalka/app/spring/api/http/error/DriverExceptionMapping.kt index 32d6f69..5ff6044 100644 --- a/botalka/src/main/kotlin/ru/vityaman/lms/botalka/app/spring/api/http/error/DriverExceptionMapping.kt +++ b/botalka/src/main/kotlin/ru/vityaman/lms/botalka/app/spring/api/http/error/DriverExceptionMapping.kt @@ -7,6 +7,7 @@ import org.springframework.http.HttpStatus import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.ExceptionHandler import org.springframework.web.bind.annotation.RestControllerAdvice +import org.springframework.web.server.ServerWebInputException import ru.vityaman.lms.botalka.app.spring.api.http.server.GeneralErrorMessage @RestControllerAdvice @@ -60,4 +61,18 @@ class DriverExceptionMapping { ), ) } + + @ExceptionHandler(ServerWebInputException::class) + fun handle(exception: ServerWebInputException) = run { + val code = HttpStatus.BAD_REQUEST + ResponseEntity + .status(code) + .body( + GeneralErrorMessage( + code = code.value(), + status = code.reasonPhrase, + message = "Input is invalid: ${exception.reason ?: ""}", + ), + ) + } } From ecf2f4c0b963115948bd673e46e4a4301b102ece Mon Sep 17 00:00:00 2001 From: vityaman Date: Tue, 30 Apr 2024 13:22:37 +0300 Subject: [PATCH 12/12] #91 Removed unused handlers --- .../api/http/error/DriverExceptionMapping.kt | 55 +------------------ 1 file changed, 1 insertion(+), 54 deletions(-) diff --git a/botalka/src/main/kotlin/ru/vityaman/lms/botalka/app/spring/api/http/error/DriverExceptionMapping.kt b/botalka/src/main/kotlin/ru/vityaman/lms/botalka/app/spring/api/http/error/DriverExceptionMapping.kt index 5ff6044..71d73b0 100644 --- a/botalka/src/main/kotlin/ru/vityaman/lms/botalka/app/spring/api/http/error/DriverExceptionMapping.kt +++ b/botalka/src/main/kotlin/ru/vityaman/lms/botalka/app/spring/api/http/error/DriverExceptionMapping.kt @@ -1,8 +1,5 @@ package ru.vityaman.lms.botalka.app.spring.api.http.error -import com.fasterxml.jackson.core.JsonParseException -import com.fasterxml.jackson.databind.JsonMappingException -import com.fasterxml.jackson.databind.exc.MismatchedInputException import org.springframework.http.HttpStatus import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.ExceptionHandler @@ -12,56 +9,6 @@ import ru.vityaman.lms.botalka.app.spring.api.http.server.GeneralErrorMessage @RestControllerAdvice class DriverExceptionMapping { - @ExceptionHandler(JsonParseException::class) - fun handle(exception: JsonParseException): ResponseEntity { - val code = HttpStatus.BAD_REQUEST - val offset = exception.location.offsetDescription() - return ResponseEntity - .status(code) - .body( - GeneralErrorMessage( - code = code.value(), - status = code.reasonPhrase, - message = "Json syntax error at $offset", - ), - ) - } - - @ExceptionHandler(JsonMappingException::class) - fun handle(exception: JsonMappingException): ResponseEntity { - val code = HttpStatus.BAD_REQUEST - val offset = exception.location?.offsetDescription() ?: "(?, ?)" - val cause = exception.cause?.message ?: "unknown cause" - return ResponseEntity - .status(code) - .body( - GeneralErrorMessage( - code = code.value(), - status = code.reasonPhrase, - message = "Json mapping error at $offset: $cause", - ), - ) - } - - @ExceptionHandler(MismatchedInputException::class) - fun handle(exception: MismatchedInputException): ResponseEntity { - val code = HttpStatus.BAD_REQUEST - val offset = exception.location?.offsetDescription() ?: "(?, ?)" - val message = buildString { - append("Json mismatched input error at $offset, ") - append("ensure that all required fields are set") - } - return ResponseEntity - .status(code) - .body( - GeneralErrorMessage( - code = code.value(), - status = code.reasonPhrase, - message = message, - ), - ) - } - @ExceptionHandler(ServerWebInputException::class) fun handle(exception: ServerWebInputException) = run { val code = HttpStatus.BAD_REQUEST @@ -71,7 +18,7 @@ class DriverExceptionMapping { GeneralErrorMessage( code = code.value(), status = code.reasonPhrase, - message = "Input is invalid: ${exception.reason ?: ""}", + message = "Input is invalid: ${exception.reason ?: "?"}", ), ) }