mirror of https://github.com/usbharu/Hideout.git
Merge pull request #286 from usbharu/feature/bean-validation
Bean Validationの導入
This commit is contained in:
commit
fd269a52e2
|
@ -197,9 +197,10 @@ dependencies {
|
||||||
implementation("org.springframework.boot:spring-boot-starter-oauth2-authorization-server")
|
implementation("org.springframework.boot:spring-boot-starter-oauth2-authorization-server")
|
||||||
implementation("org.springframework.boot:spring-boot-starter-oauth2-resource-server")
|
implementation("org.springframework.boot:spring-boot-starter-oauth2-resource-server")
|
||||||
implementation("org.springframework.boot:spring-boot-starter-log4j2")
|
implementation("org.springframework.boot:spring-boot-starter-log4j2")
|
||||||
compileOnly("jakarta.validation:jakarta.validation-api")
|
implementation("org.springframework.boot:spring-boot-starter-validation")
|
||||||
compileOnly("jakarta.annotation:jakarta.annotation-api:2.1.0")
|
implementation("jakarta.validation:jakarta.validation-api")
|
||||||
compileOnly("io.swagger.core.v3:swagger-annotations:2.2.6")
|
implementation("jakarta.annotation:jakarta.annotation-api:2.1.0")
|
||||||
|
implementation("io.swagger.core.v3:swagger-annotations:2.2.6")
|
||||||
implementation("io.swagger.core.v3:swagger-models:2.2.6")
|
implementation("io.swagger.core.v3:swagger-models:2.2.6")
|
||||||
implementation("org.jetbrains.exposed:exposed-java-time:$exposed_version")
|
implementation("org.jetbrains.exposed:exposed-java-time:$exposed_version")
|
||||||
testImplementation("org.springframework.boot:spring-boot-starter-test")
|
testImplementation("org.springframework.boot:spring-boot-starter-test")
|
||||||
|
|
|
@ -24,6 +24,7 @@ import org.assertj.core.api.Assertions.assertThat
|
||||||
import org.flywaydb.core.Flyway
|
import org.flywaydb.core.Flyway
|
||||||
import org.junit.jupiter.api.AfterAll
|
import org.junit.jupiter.api.AfterAll
|
||||||
import org.junit.jupiter.api.BeforeEach
|
import org.junit.jupiter.api.BeforeEach
|
||||||
|
import org.junit.jupiter.api.Disabled
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
import org.springframework.beans.factory.annotation.Autowired
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc
|
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc
|
||||||
|
@ -31,7 +32,6 @@ import org.springframework.boot.test.context.SpringBootTest
|
||||||
import org.springframework.http.MediaType
|
import org.springframework.http.MediaType
|
||||||
import org.springframework.security.core.authority.SimpleGrantedAuthority
|
import org.springframework.security.core.authority.SimpleGrantedAuthority
|
||||||
import org.springframework.security.test.context.support.WithAnonymousUser
|
import org.springframework.security.test.context.support.WithAnonymousUser
|
||||||
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors
|
|
||||||
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf
|
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf
|
||||||
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.jwt
|
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.jwt
|
||||||
import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity
|
import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity
|
||||||
|
@ -160,6 +160,7 @@ class AccountApiTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@Disabled("JSONでも作れるようにするため")
|
||||||
@WithAnonymousUser
|
@WithAnonymousUser
|
||||||
fun apiV1AccountsPostでJSONで作ろうとしても400() {
|
fun apiV1AccountsPostでJSONで作ろうとしても400() {
|
||||||
mockMvc
|
mockMvc
|
||||||
|
|
|
@ -19,6 +19,7 @@ package dev.usbharu.hideout.generate
|
||||||
import org.slf4j.Logger
|
import org.slf4j.Logger
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.core.MethodParameter
|
import org.springframework.core.MethodParameter
|
||||||
|
import org.springframework.validation.BindException
|
||||||
import org.springframework.web.bind.support.WebDataBinderFactory
|
import org.springframework.web.bind.support.WebDataBinderFactory
|
||||||
import org.springframework.web.context.request.NativeWebRequest
|
import org.springframework.web.context.request.NativeWebRequest
|
||||||
import org.springframework.web.method.annotation.ModelAttributeMethodProcessor
|
import org.springframework.web.method.annotation.ModelAttributeMethodProcessor
|
||||||
|
@ -56,12 +57,17 @@ class JsonOrFormModelMethodProcessor(
|
||||||
|
|
||||||
return try {
|
return try {
|
||||||
modelAttributeMethodProcessor.resolveArgument(parameter, mavContainer, webRequest, binderFactory)
|
modelAttributeMethodProcessor.resolveArgument(parameter, mavContainer, webRequest, binderFactory)
|
||||||
|
} catch (e: BindException) {
|
||||||
|
throw e
|
||||||
} catch (exception: Exception) {
|
} catch (exception: Exception) {
|
||||||
try {
|
try {
|
||||||
requestResponseBodyMethodProcessor.resolveArgument(parameter, mavContainer, webRequest, binderFactory)
|
requestResponseBodyMethodProcessor.resolveArgument(parameter, mavContainer, webRequest, binderFactory)
|
||||||
|
} catch (e: BindException) {
|
||||||
|
throw e
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
logger.warn("Failed to bind request (1)", exception)
|
logger.warn("Failed to bind request (1)", exception)
|
||||||
logger.warn("Failed to bind request (2)", e)
|
logger.warn("Failed to bind request (2)", e)
|
||||||
|
throw IllegalArgumentException("Failed to bind request.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,19 +59,19 @@ class MastodonAccountApiController(
|
||||||
HttpStatus.OK
|
HttpStatus.OK
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun apiV1AccountsPost(
|
override suspend fun apiV1AccountsPost(accountsCreateRequest: AccountsCreateRequest): ResponseEntity<Unit> {
|
||||||
username: String,
|
|
||||||
password: String,
|
|
||||||
email: String?,
|
|
||||||
agreement: Boolean?,
|
|
||||||
locale: Boolean?,
|
|
||||||
reason: String?
|
|
||||||
): ResponseEntity<Unit> {
|
|
||||||
transaction.transaction {
|
transaction.transaction {
|
||||||
accountApiService.registerAccount(UserCreateDto(username, username, "", password))
|
accountApiService.registerAccount(
|
||||||
|
UserCreateDto(
|
||||||
|
accountsCreateRequest.username,
|
||||||
|
accountsCreateRequest.username,
|
||||||
|
"",
|
||||||
|
accountsCreateRequest.password
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
val httpHeaders = HttpHeaders()
|
val httpHeaders = HttpHeaders()
|
||||||
httpHeaders.location = URI("/users/$username")
|
httpHeaders.location = URI("/users/${accountsCreateRequest.username}")
|
||||||
return ResponseEntity(Unit, httpHeaders, HttpStatus.FOUND)
|
return ResponseEntity(Unit, httpHeaders, HttpStatus.FOUND)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -276,6 +276,9 @@ paths:
|
||||||
requestBody:
|
requestBody:
|
||||||
required: true
|
required: true
|
||||||
content:
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/AccountsCreateRequest"
|
||||||
application/x-www-form-urlencoded:
|
application/x-www-form-urlencoded:
|
||||||
schema:
|
schema:
|
||||||
$ref: "#/components/schemas/AccountsCreateRequest"
|
$ref: "#/components/schemas/AccountsCreateRequest"
|
||||||
|
@ -1355,6 +1358,7 @@ components:
|
||||||
format: binary
|
format: binary
|
||||||
description:
|
description:
|
||||||
type: string
|
type: string
|
||||||
|
maxLength: 4000
|
||||||
focus:
|
focus:
|
||||||
type: string
|
type: string
|
||||||
required:
|
required:
|
||||||
|
@ -1365,12 +1369,18 @@ components:
|
||||||
properties:
|
properties:
|
||||||
username:
|
username:
|
||||||
type: string
|
type: string
|
||||||
|
minLength: 1
|
||||||
|
maxLength: 300
|
||||||
|
pattern: '^[a-zA-Z0-9_-]{1,300}$'
|
||||||
email:
|
email:
|
||||||
type: string
|
type: string
|
||||||
|
format: email
|
||||||
password:
|
password:
|
||||||
type: string
|
type: string
|
||||||
|
format: password
|
||||||
agreement:
|
agreement:
|
||||||
type: boolean
|
type: boolean
|
||||||
|
default: false
|
||||||
locale:
|
locale:
|
||||||
type: boolean
|
type: boolean
|
||||||
reason:
|
reason:
|
||||||
|
@ -1399,6 +1409,8 @@ components:
|
||||||
type: string
|
type: string
|
||||||
username:
|
username:
|
||||||
type: string
|
type: string
|
||||||
|
minLength: 1
|
||||||
|
pattern: '^[a-zA-Z0-9_-]{1,300}$'
|
||||||
acct:
|
acct:
|
||||||
type: string
|
type: string
|
||||||
url:
|
url:
|
||||||
|
@ -1968,8 +1980,10 @@ components:
|
||||||
properties:
|
properties:
|
||||||
phrase:
|
phrase:
|
||||||
type: string
|
type: string
|
||||||
|
maxLength: 1000
|
||||||
context:
|
context:
|
||||||
type: array
|
type: array
|
||||||
|
maxItems: 10
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
enum:
|
enum:
|
||||||
|
@ -1980,8 +1994,10 @@ components:
|
||||||
- account
|
- account
|
||||||
irreversible:
|
irreversible:
|
||||||
type: boolean
|
type: boolean
|
||||||
|
default: false
|
||||||
whole_word:
|
whole_word:
|
||||||
type: boolean
|
type: boolean
|
||||||
|
default: false
|
||||||
expires_in:
|
expires_in:
|
||||||
type: integer
|
type: integer
|
||||||
required:
|
required:
|
||||||
|
@ -1993,8 +2009,10 @@ components:
|
||||||
properties:
|
properties:
|
||||||
phrase:
|
phrase:
|
||||||
type: string
|
type: string
|
||||||
|
maxLength: 1000
|
||||||
context:
|
context:
|
||||||
type: array
|
type: array
|
||||||
|
maxItems: 10
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
enum:
|
enum:
|
||||||
|
@ -2015,8 +2033,10 @@ components:
|
||||||
properties:
|
properties:
|
||||||
title:
|
title:
|
||||||
type: string
|
type: string
|
||||||
|
maxLength: 255
|
||||||
context:
|
context:
|
||||||
type: array
|
type: array
|
||||||
|
maxItems: 10
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
enum:
|
enum:
|
||||||
|
@ -2033,6 +2053,7 @@ components:
|
||||||
expires_in:
|
expires_in:
|
||||||
type: integer
|
type: integer
|
||||||
keywords_attributes:
|
keywords_attributes:
|
||||||
|
maxItems: 1000
|
||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
$ref: "#/components/schemas/FilterPostRequestKeyword"
|
$ref: "#/components/schemas/FilterPostRequestKeyword"
|
||||||
|
@ -2045,6 +2066,7 @@ components:
|
||||||
properties:
|
properties:
|
||||||
keyword:
|
keyword:
|
||||||
type: string
|
type: string
|
||||||
|
maxLength: 1000
|
||||||
whole_word:
|
whole_word:
|
||||||
type: boolean
|
type: boolean
|
||||||
default: false
|
default: false
|
||||||
|
@ -2059,6 +2081,7 @@ components:
|
||||||
properties:
|
properties:
|
||||||
keyword:
|
keyword:
|
||||||
type: string
|
type: string
|
||||||
|
maxLength: 1000
|
||||||
whole_word:
|
whole_word:
|
||||||
type: boolean
|
type: boolean
|
||||||
default: false
|
default: false
|
||||||
|
@ -2073,6 +2096,7 @@ components:
|
||||||
properties:
|
properties:
|
||||||
keyword:
|
keyword:
|
||||||
type: string
|
type: string
|
||||||
|
maxLength: 1000
|
||||||
whole_word:
|
whole_word:
|
||||||
type: boolean
|
type: boolean
|
||||||
regex:
|
regex:
|
||||||
|
@ -2083,8 +2107,10 @@ components:
|
||||||
properties:
|
properties:
|
||||||
title:
|
title:
|
||||||
type: string
|
type: string
|
||||||
|
maxLength: 255
|
||||||
context:
|
context:
|
||||||
type: array
|
type: array
|
||||||
|
maxItems: 10
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
enum:
|
enum:
|
||||||
|
@ -2101,6 +2127,7 @@ components:
|
||||||
expires_in:
|
expires_in:
|
||||||
type: integer
|
type: integer
|
||||||
keywords_attributes:
|
keywords_attributes:
|
||||||
|
maxItems: 1000
|
||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
$ref: "#/components/schemas/FilterPubRequestKeyword"
|
$ref: "#/components/schemas/FilterPubRequestKeyword"
|
||||||
|
@ -2110,6 +2137,7 @@ components:
|
||||||
properties:
|
properties:
|
||||||
keyword:
|
keyword:
|
||||||
type: string
|
type: string
|
||||||
|
maxLength: 1000
|
||||||
whole_word:
|
whole_word:
|
||||||
type: boolean
|
type: boolean
|
||||||
regex:
|
regex:
|
||||||
|
@ -2118,6 +2146,9 @@ components:
|
||||||
type: string
|
type: string
|
||||||
_destroy:
|
_destroy:
|
||||||
type: boolean
|
type: boolean
|
||||||
|
default: false
|
||||||
|
required:
|
||||||
|
- id
|
||||||
|
|
||||||
FilterStatusRequest:
|
FilterStatusRequest:
|
||||||
type: object
|
type: object
|
||||||
|
@ -2473,18 +2504,22 @@ components:
|
||||||
status:
|
status:
|
||||||
type: string
|
type: string
|
||||||
nullable: true
|
nullable: true
|
||||||
|
maxLength: 3000
|
||||||
media_ids:
|
media_ids:
|
||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
|
maxItems: 4
|
||||||
poll:
|
poll:
|
||||||
$ref: "#/components/schemas/StatusesRequestPoll"
|
$ref: "#/components/schemas/StatusesRequestPoll"
|
||||||
in_reply_to_id:
|
in_reply_to_id:
|
||||||
type: string
|
type: string
|
||||||
sensitive:
|
sensitive:
|
||||||
type: boolean
|
type: boolean
|
||||||
|
default: false
|
||||||
spoiler_text:
|
spoiler_text:
|
||||||
type: string
|
type: string
|
||||||
|
maxLength: 100
|
||||||
visibility:
|
visibility:
|
||||||
type: string
|
type: string
|
||||||
enum:
|
enum:
|
||||||
|
@ -2494,22 +2529,29 @@ components:
|
||||||
- direct
|
- direct
|
||||||
language:
|
language:
|
||||||
type: string
|
type: string
|
||||||
|
maxLength: 100
|
||||||
scheduled_at:
|
scheduled_at:
|
||||||
type: string
|
type: string
|
||||||
|
format: date-time
|
||||||
|
example: "2019-12-05T12:33:01.000Z"
|
||||||
|
|
||||||
StatusesRequestPoll:
|
StatusesRequestPoll:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
options:
|
options:
|
||||||
type: array
|
type: array
|
||||||
|
maxItems: 10
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
|
maxLength: 100
|
||||||
expires_in:
|
expires_in:
|
||||||
type: integer
|
type: integer
|
||||||
multiple:
|
multiple:
|
||||||
type: boolean
|
type: boolean
|
||||||
|
default: false
|
||||||
hide_totals:
|
hide_totals:
|
||||||
type: boolean
|
type: boolean
|
||||||
|
default: false
|
||||||
|
|
||||||
Application:
|
Application:
|
||||||
type: object
|
type: object
|
||||||
|
@ -2536,12 +2578,16 @@ components:
|
||||||
properties:
|
properties:
|
||||||
client_name:
|
client_name:
|
||||||
type: string
|
type: string
|
||||||
|
maxLength: 200
|
||||||
redirect_uris:
|
redirect_uris:
|
||||||
type: string
|
type: string
|
||||||
|
maxLength: 1000
|
||||||
scopes:
|
scopes:
|
||||||
type: string
|
type: string
|
||||||
|
maxLength: 1000
|
||||||
website:
|
website:
|
||||||
type: string
|
type: string
|
||||||
|
maxLength: 1000
|
||||||
required:
|
required:
|
||||||
- client_name
|
- client_name
|
||||||
- redirect_uris
|
- redirect_uris
|
||||||
|
@ -2602,16 +2648,20 @@ components:
|
||||||
default: false
|
default: false
|
||||||
languages:
|
languages:
|
||||||
type: array
|
type: array
|
||||||
|
maxItems: 10
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
|
maxLength: 10
|
||||||
|
|
||||||
UpdateCredentials:
|
UpdateCredentials:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
display_name:
|
display_name:
|
||||||
type: string
|
type: string
|
||||||
|
maxLength: 300
|
||||||
note:
|
note:
|
||||||
type: string
|
type: string
|
||||||
|
maxLength: 2000
|
||||||
avatar:
|
avatar:
|
||||||
type: string
|
type: string
|
||||||
format: binary
|
format: binary
|
||||||
|
|
Loading…
Reference in New Issue