Skip to content

Commit

Permalink
Added javascript (AJAX) validation of forms in preparation for regist…
Browse files Browse the repository at this point in the history
…ration process
  • Loading branch information
martinlau committed Jul 17, 2013
1 parent 5c5b683 commit aaf8589
Show file tree
Hide file tree
Showing 12 changed files with 539 additions and 9 deletions.
25 changes: 25 additions & 0 deletions src/main/annotation/org/springframework/http/annotations.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
#%L
fixture
%%
Copyright (C) 2013 Martin Lau
%%
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
#L%
-->
<root>
<item name='org.springframework.http.HttpEntity org.springframework.http.HttpHeaders getHeaders()'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
</root>
38 changes: 38 additions & 0 deletions src/main/annotation/org/springframework/validation/annotations.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
#%L
fixture
%%
Copyright (C) 2013 Martin Lau
%%
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
#L%
-->
<root>
<item name="org.springframework.validation.Errors java.util.List&lt;org.springframework.validation.FieldError&gt; getFieldErrors()">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
<item name="org.springframework.validation.Errors java.util.List&lt;org.springframework.validation.ObjectError&gt; getAllErrors()">
<annotation name="org.jetbrains.annotations.NotNull"/>
<annotation name="jet.runtime.typeinfo.KotlinSignature">
<val name="value" val="&quot;fun getAllErrors(): List&lt;ObjectError&gt;&quot;"/>
</annotation>
</item>
<item name="org.springframework.validation.FieldError java.lang.String getField()">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
<item name="org.springframework.validation.ObjectError java.lang.String getObjectName()">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
</root>

25 changes: 25 additions & 0 deletions src/main/annotation/org/springframework/web/bind/annotations.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
#%L
fixture
%%
Copyright (C) 2013 Martin Lau
%%
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
#L%
-->
<root>
<item name='org.springframework.web.bind.MethodArgumentNotValidException org.springframework.validation.BindingResult getBindingResult()'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
</root>
13 changes: 12 additions & 1 deletion src/main/kotlin/io/fixture/controller/RegistrationController.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,22 @@ package io.fixture.controller

import org.springframework.stereotype.Controller
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.ModelAttribute
import javax.validation.constraints.NotNull
import org.hibernate.validator.constraints.Length
import org.hibernate.validator.constraints.NotEmpty
import org.hibernate.validator.constraints.ScriptAssert
import javax.validation.constraints.AssertTrue
import org.hibernate.validator.constraints.Email
import io.fixture.controller.form.RegistrationForm

[Controller]
[RequestMapping(value = array("join"))]
[RequestMapping(value = array("/register"))]
public class RegistrationController {

[ModelAttribute]
fun registrationForm() = RegistrationForm()

[RequestMapping]
fun index() = ".registration.index"

Expand Down
87 changes: 87 additions & 0 deletions src/main/kotlin/io/fixture/controller/ValidationController.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
* #%L
* fixture
* %%
* Copyright (C) 2013 Martin Lau
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/

package io.fixture.controller

import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.stereotype.Controller
import org.springframework.web.bind.annotation.ExceptionHandler
import org.springframework.web.bind.MethodArgumentNotValidException
import java.util.HashMap
import org.springframework.web.bind.annotation.RequestBody
import javax.validation.Valid
import org.springframework.web.bind.annotation.ResponseBody
import io.fixture.controller.form.RegistrationForm
import org.springframework.web.bind.annotation.RequestMethod
import org.springframework.http.MediaType
import org.springframework.validation.FieldError
import java.util.LinkedList
import java.util.Collections

[Controller]
[RequestMapping(value = array("/validate"))]
public class ValidationController {

val valid = Collections.emptyMap<String, List<String?>>()

// To test this:
// $.ajax({
// type: 'POST',
// url: '/fixture/validate/join.json',
// contentType: 'application/json',
// data: JSON.stringify({
// "username":"blah",
// "password":"blah",
// "confirm":"blah",
// "familyName":"blah",
// "givenName":"blah",
// "email":"email@blah.com",
// "accept":false
// }),
// success: function(data) {
// console.log(data);
// }
// });

[RequestMapping(
method = array(RequestMethod.POST),
value = array("/register")
)]
[ResponseBody]
fun validateRegistrationForm([Valid] [RequestBody] form: RegistrationForm) = valid

[ExceptionHandler]
[ResponseBody]
fun handleValidationError(exception: MethodArgumentNotValidException): Map<String, List<String?>> {

val errors = HashMap<String, MutableList<String?>>()

exception.getBindingResult().getAllErrors().forEach {

val message = it.getDefaultMessage()
val name = if (it is FieldError) it.getField() else "*"

errors.getOrPut(name) { LinkedList() }.add(message)
}

return errors
}

}
59 changes: 59 additions & 0 deletions src/main/kotlin/io/fixture/controller/form/RegistrationForm.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* #%L
* fixture
* %%
* Copyright (C) 2013 Martin Lau
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/

package io.fixture.controller.form

import org.hibernate.validator.constraints.ScriptAssert
import org.hibernate.validator.constraints.NotEmpty
import org.hibernate.validator.constraints.Email
import org.hibernate.validator.constraints.Length
import javax.validation.constraints.NotNull
import javax.validation.constraints.AssertTrue

[ScriptAssert(
lang = "javascript",
script = "_this.password == _this.confirm"
)]
class RegistrationForm(

[NotEmpty]
var givenName: String? = null,

[NotEmpty]
var familyName: String? = null,

[Email]
[NotNull]
var email: String? = null,

[NotEmpty]
var username: String? = null,

[NotEmpty]
var password: String? = null,

[NotEmpty]
var confirm: String? = null,

[AssertTrue]
[NotNull]
var accept: Boolean? = null

)
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ common.footer.terms-of-use=Terms of use
common.navigation.index=fixture.io
common.navigation.about=About
common.navigation.contact=Contact
common.navigation.join=Join
common.navigation.login=Log in
common.navigation.logout=Log out
common.navigation.register=Register

registration.title=Join

Expand Down
4 changes: 2 additions & 2 deletions src/main/webapp/WEB-INF/jspx/common/navigation.jspx
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@
</navigation:li_a>
</security:authorize>
<security:authorize access="isAnonymous()">
<navigation:li_a href="/join">
<spring:message code="common.navigation.join" />
<navigation:li_a href="/register">
<spring:message code="common.navigation.register" />
</navigation:li_a>
<navigation:li_a href="/login">
<spring:message code="common.navigation.login" />
Expand Down
4 changes: 2 additions & 2 deletions src/main/webapp/WEB-INF/tiles.xml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
<add-attribute value="/resources/fixture.css"/>
</put-list-attribute>
<put-list-attribute name="bodyScripts" cascade="true" inherit="true">
<add-attribute value="/static/jquery/2.0.2/jquery.min.js"/>
<add-attribute value="/static/jquery/2.0.3/jquery.min.js"/>
<add-attribute value="/static/bootswatch/2.3.1/js/bootstrap.min.js"/>
<add-attribute value="/static/bootswatch/2.3.1/js/bootswatch.js"/>
</put-list-attribute>
Expand All @@ -55,7 +55,7 @@

<definition name=".registration.index" extends=".base.template">
<put-attribute name="body" type="template" value="/WEB-INF/jspx/registration/index.jspx"/>
<put-attribute name="title" type="string" value="fixture.io - Join"/>
<put-attribute name="title" type="string" value="fixture.io - Register"/>
</definition>

<definition name=".secure.index" extends=".base.template">
Expand Down
49 changes: 49 additions & 0 deletions src/test/kotlin/io/fixture/controller/ValidationControllerTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* #%L
* fixture
* %%
* Copyright (C) 2013 Martin Lau
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/

package io.fixture.controller

import kotlin.test.assertEquals
import org.junit.Test
import org.springframework.web.bind.MethodArgumentNotValidException
import org.springframework.validation.MapBindingResult
import java.util.HashMap
import org.springframework.validation.ObjectError
import org.springframework.validation.FieldError

class ValidationControllerTest {

val subject = ValidationController()

[Test]
fun testHandleValidationError() {
val bindingResult = MapBindingResult(HashMap<Any?, Any?>(), "test")
bindingResult.addError(ObjectError("objectName", "must be set"))
bindingResult.addError(ObjectError("objectName", "must be valid"))
bindingResult.addError(FieldError("objectName", "fieldName", "must not be set"))

val result = subject.handleValidationError(MethodArgumentNotValidException(null, bindingResult))

assertEquals(2, result.size)
assertEquals(result.get("*"), listOf("must be set", "must be valid"))
assertEquals(result.get("fieldName"), listOf("must not be set"))
}

}
Loading

0 comments on commit aaf8589

Please sign in to comment.