Play Validation - Custom form field validation with specific field error - validation

case class Address(
address1: String,
city: String,
state: String,
postal: String,
country: String
)
Form(
mapping = mapping(
"address1" -> nonEmptyText,
"city" -> nonEmptyText,
"state" -> nonEmptyText,
"postal" -> nonEmptyText,
"country" -> nonEmptyText
)(Address.apply)(Address.unapply).verifying("Invalid Postal Code!", validatePostal _)
)
def validatePostal(address: Address): Boolean = {
address.country match {
case "US" | "CA" =>
val regex: Regex = ("^(\\d{5}-\\d{4}|\\d{5}|\\d{9})$|^([a-zA-Z]\\d[a-zA-Z]( )?\\d[a-zA-Z]\\d)$").r
regex.pattern.matcher(address.postal).matches()
case _ => false
}
}
Above form validation for postal code works fine with global error displayed on form for invalid US or Canadian postal codes.
I would like to show the error as field error right next to the field than as global error which in my case is shown on top of the form.
Is there a way to use inbuilt Form constraints or verification methods to achieve this instead of FormError's?

You can add the constraint to the field. Then update validatePostal to accept a tuple of the two values instead.
Form(
mapping = mapping(
"address1" -> nonEmptyText,
"city" -> nonEmptyText,
"state" -> nonEmptyText,
"postal" -> tuple(
"code" -> nonEmptyText,
"country" -> nonEmptyText
).verifying("Invalid Postal Code!", validatePostal _),
)((address1, city, state, postal) => Address(address1, city, state, postal._1, postal._2))((address: Address) => Some((address.address1, address.city, address.state, (address.postal, address.country))))
)
Template:
#inputText(
addressForm("postal.code"),
'_label -> "Postal code",
'_help -> "Please enter a valid postal code.",
'_error -> addressForm.error("postal")
)

Defining the error like that you are creating a FormError("","Invalid Postal Code!") object in a form, as it doesn't have key (the first parameter), the framework don't attach the error to the form element.
On form error when you are binding the request to the form, you will have to create a new form removing the FormError("","Invalid Postal Code!") and replacing it with an error FormError("form.id","message")
In our project we created an implicit def for Form to replace the form errors (we couldn't find a way to create dynamic constraint validations) these are the 2 definitions we have:
def replaceError(key: String, newError: FormError): Form[T] = {
val updatedFormErrors = form.errors.flatMap { fe =>
if (fe.key == key) {
if (form.error(newError.key).isDefined) None
else {
if (newError.args.isEmpty ) Some(FormError(newError.key,newError.message,fe.args))
else Some(newError)
}
} else {
Some(fe)
}
}
form.copy(errors = updatedFormErrors.foldLeft(Seq[FormError]()) { (z, fe) =>
if (z.groupBy(_.key).contains(fe.key)) z else z :+ fe
})
}
def replaceError(key: String, message: String, newError: FormError): Form[T] = {
def matchingError(e: FormError) = e.key == key && e.message == message
val oldError = form.errors.find(matchingError)
if (oldError.isDefined) {
val error = if (newError.args.isEmpty) FormError(newError.key,newError.message,oldError.get.args) else newError
form.copy(errors = form.errors.filterNot(e => e.key == key && e.message == message)).withError(error)
}
else form
}
We have those in a class called FormCryptBind (because we also improve the form object with some crypto stuff) and we define the implicit def like this:
implicit def formBinding[T](form: Form[T])(implicit request: Request[_]) = new FormCryptBind[T](form)
We do it like that because just importing the object having this implicit definition, you can use all the FormCryptBind definitions as they were Form's
And we use it like this
import whatever.FormImprovements._
...
object SomeController extends Controller{
...
def submit = Action{ implicit request =>
form.bindRequest.fold(
formWithErrors => {
val newForm = formWithErrors.replaceError("", "formField.required", FormError("formField", "error.required")
BadRequest(someView(newForm)
},
formDetails => Redirect(anotherView(formDetails))
}
As I can't put actual live code from the app, I touched it a little bit :D so expect compile errors if you copy & paste

Related

How to remove the nested input object in the Graphene Django mutation query (Relay)?

I want to create a Mutation in Relay. I'm using InputObjectType pattern to separate the input and make it reusable.
In mutation class I'm using Input class and there I'm passing the InputObjectType
In general it works but the final query at the client side is very ugly.
I need to pass arguments in this way
query( input : { input : { ...arguments } } )
and to be honest I don't like it. I think it looks ugly.
So the question is: Is it possible to avoid to use a lot of these input objects?
It's ok to use 1 input object, but the nested one is redundant and I'd like to avoid to use it.
Thanks for any help!
Here is the example
class FuelTypeInput(graphene.InputObjectType):
id = graphene.Int()
label = graphene.String()
class FuelSubtypeInput(graphene.InputObjectType):
id = graphene.ID()
label = graphene.String()
fuel_type = graphene.Field(FuelTypeInput)
class CreateFuelSubType(relay.ClientIDMutation):
class Input:
input = FuelSubtypeInput(required=True)
fuel_subtype = Field(FuelSubTypeNode)
ok = graphene.Boolean()
def mutate_and_get_payload(root, info, input):
label = input.label
fuel_type = FuelType.objects.get(pk=input.fuel_type.id)
fuel_subtype = FuelSubType(label=label, fuel_type=fuel_type)
ok = True
return CreateFuelSubType(fuel_subtype=fuel_subtype, ok=ok)
The mutation query is:
mutation MyMutations {
createFuelSubtype( input: { input : { label: "Mutation Subtype", fuelType: {
id: 3
}} } ) {
fuelSubtype {
label
}
ok
}
}
It works fine, here is the result. But I'd like to remove the nested input things
{
"data": {
"createFuelSubtype": {
"fuelSubtype": {
"label": "Mutation Subtype"
},
"ok": true
}
}
}
you can fix with this:
class FuelTypeInput(graphene.AbstractType):
id = graphene.Int()
label = graphene.String()
class CreateFuelSubType(relay.ClientIDMutation):
Input = FuelSubtypeInput
fuel_subtype = Field(FuelSubTypeNode)
ok = graphene.Boolean()
# Other Code ...

Return any data from a query using GraphQL, Graphene and Python

I am receiving the following error:
{
"errors": [
{
"message": "Unknown argument \"project_id\" on field" +
\"get_project_detail_summary\" of type \"Query\".",
"locations": [
{
"line": 2,
"column": 30
}
]
}
]
}
With the following query:
query GetProjectDetailSummary($project_id: Int) {
get_project_detail_summary(project_id: $project_id) {
comments {
... on ManagerCommentNode {
id
text
created
}
... on VendorCommentNode {
id
text
created
}
... on TenantCommentNode {
id
text
created
}
}
}
}
With the following backend code, How can I get to the breakpoint?, or how do I send back custom data given a number?:
class CommentsUnion(graphene.types.union.Union):
class Meta:
name = 'CommentsUnion'
types = (ManagerCommentNode, VendorCommentNode, TenantCommentNode, )
class ProjectSummaryInput(graphene.InputObjectType):
project_id = graphene.Int()
class ProjectSummaryNode(graphene.ObjectType):
Input = ProjectSummaryInput
project_id = graphene.Int()
comments = graphene.List(CommentsUnion)
#classmethod
def resolve_comments(self, *args, **kwargs):
import pdb;pdb.set_trace()
return ProjectSummary.select_related('comments').objects.filter(comments__created__lt=dt)
class Query(graphene.ObjectType):
get_project_detail_summary = Field(ProjectSummaryNode)
In regards to the error.
Be sure to add a kwarg ( e.g. project_id in this example, it is the reason for the "unknown argument on field" error ) to the graphene.Field for get_project_detail_summary.
Like so:
class Query(graphene.ObjectType):
get_project_detail_summary = Field(ProjectSummaryNode, # see below for example
project_id=graphene.Int() # kwarg here
)
def resolve_get_project_detail_summary(self, info, **kwargs):
return ProjectSummary.objects.get(id=kwargs.get('project_id'))
In regards to returning any data.
This is a way ( returning a graphene.String ), but it untypes the response by putting everything inside a String:
from django.core.serializers.json import DjangoJSONEncoder
class ProjectSummaryRecentUpdatesNode(graphene.ObjectType):
Input = ProjectSummaryInput
recent_updates = graphene.String()
def resolve_recent_updates(self, resolve, **kwargs):
instance = Project.objects.get(id=resolve.variable_values.get("project_id"))
things = instance.things.all()
# these are all from different models, and the list is a bit longer than this.
querysets = (
("scheduled", get_scheduled(things, resolve, **kwargs)),
("completed", get_completed(things, resolve, **kwargs)),
("invoices", get_invoices(things, resolve, **kwargs)),
("expenditures", get_expenditures(things, resolve, **kwargs)),
("comments", get_comments(things, resolve, **kwargs)),
("files", get_files(things, resolve, **kwargs)),
)
recent_updates = []
for update_type, qs in querysets:
for item in qs:
item.update(
{
"recent_update_type": update_type
}
)
recent_updates.append(item)
return json.dumps(recent_updates, cls=DjangoJSONEncoder)
And on the frontend, with an import { Query } from "react-apollo"; element we can JSON.parse the field ... which has "any" (json serialized) data inside of it:
<Query
query={GET_PROJECT_DETAIL_SUMMARY_RECENT_UPDATES}
fetchPolicy="network-only"
variables={{ project_id: this.props.projectId }}
>
{({ loading, error, data }: QueryResult) => {
if (
data &&
data.get_project_detail_summary_recent_updates &&
data.get_project_detail_summary_recent_updates.recent_updates
) {
console.log(JSON.parse(data.get_project_detail_summary_recent_updates.recent_updates))
}
}}
</Query>
Side note:
If there isn't a large list of data types create a Union like object which has all of the fields needed from different models, or an actual Union, which seems like the correct way, as then types are not lost:
class ProjectSummaryNode(graphene.ObjectType):
# from FileNode graphene.ObjectType class
file__id = graphene.Int()
file__brief_description = graphene.String()
file_count = graphene.Int()
last_file_created = graphene.String()
last_file = graphene.String()
# from UploaderNode graphene.ObjectType class
uploader__first_name = graphene.String()
uploader__last_name = graphene.String()
# from CommentNode graphene.ObjectType class
comment = graphene.String()
class Meta:
name = "ProjectSummaryNode"
# example of Union, the above fields would be commented out, as they are part of
# the different graphene.ObjectType classes, and this line below would be uncommented
# types = ( FileNode, UploaderNode, CommentNode, )
Still open to suggestions on a better way to do this.

cleanest & best way to handle custom error in scala with lesser match clauses

I'm trying to find the best and cleanest way to handle custom errors in scala.
At present I've a common Global error object (my code looks similar to this):
sealed trait AppError {
def message: String
}
object AppError {
/* Cat Error Messages */
case class CatNotFound(id: Long) extends AppError {
val message = Messages("cat.not_found").format(id)
}
case class CatNotForUser(id: Long) extends AppError {
val message = Messages("cat.not_for_user").format(id)
}
}
Every method is returning Either[<SomeValidType>, AppError] (I'm sending error in right side) for example:
def getCatForUser(id: Long, user: User): Either[Boolean, AppError] = {
CatService get(id) match {
case None => CatNotFound(id)
case Some(x) =>
CatService isAccessibleByUser(x, user) match {
case false => CatNotForUser(id)
case true => true
}
}
}
The method which is calling the validation/get part have a lot of nested match like this:
def something(id: Long, user: User) = {
getCatForUser(id, user) match {
case Left(b) =>
anotherMethodReturnsEither(id) match {
case Left(x) =>
thereCanBeLotOfNesting(user) match {
case Left(y) =>
// do something or create another nesting call
case Right(e) =>
handleSomeHow(e)
}
case Right(e) =>
handleSomeHow(e)
}
case Right(e) =>
handleSomeHow(e)
}
}
def handleSomeHow(e: AppError) = {
e match {
case CatNotFound(_) => NotFound(e.message)
case CatNotForUser(_) => Unauthorized(e.message)
}
}
In one project I was using CustomExceptions to handle such nesting/if else. In that case I was throwing errors which were propagated to the top where they can be handled together. The code looks clean when we are using exceptions instead of errors. But I think its a problem with exceptions when you are validating data & have a method like this that doesn't return anything but throw Exception:
def validateCatForUser(id: Long, user: User) = {
CatService get(id) match {
case None => throw CatNotFound(id)
case Some(x) =>
CatService isAccessibleByUser(x, user) match {
case false => throw CatNotForUser(id)
case true => // nothing can be returned as its validation
}
}
}
and I'll use it like:
def something(id: Long, user: User) = {
validateCatForUser(id, user)
/*
* here will be some logic after validation
*/
}
Still its clean and readable. So my question is what should I use to achieve a more readable code with less match clause having Left() or Right(). I was reading about scala validation and found http://blog.lunatech.com/2012/03/02/validation-scala but scala 'Validation' also returns ValidationNEL[String, <some valid type>] which doesn't reduce match clause. The best way to handle custom errors, in my situation, according to you would be?
for comprehensions really help with the readability/nesting issue when working with Either. You can use left and right to project the Eithers and yield an Either that will collect the error:
val x = Left(5) : Either[Int, String]
val y = Right("error") : Either[Int, String]
val z = Right("error") : Either[Int, String]
for {
xval <- x.left
yval <- y.left
zval <- z.left
} yield zval
Your nested version could be made much cleaner using this syntax. It might look something like this:
def something(id: Long, user: User) = {
for {
cat <- getCatForUser(id, user).left
otherValues <- anotherMethodReturnsEither(id).left
noNesting <- thereCanBeLotOfNesting(user).left
} yield noNesting
} match {
case Left(value) => // do something
case Right(e) => handleSomeHow(e)
}
You should switch to Scalaz's \/ (I call it 'Scalaz Either', or 'Or') and move your 'happy path' to the right side.
\/ is right-side biased which allows you to use it in for-comprehensions. You can write:
for {
resA <- computeA()
resB <- computeB(resA)
} yield resB
where computeX return \/[Error, X].

Conditional mapping in play scala

Using play 2.x, I have the following Form mapping:
val relocationDtoForm: Form[RelocationDto] = Form(
mapping(
"_type" -> text,
"sourceToken" -> text,
"exchange" -> optional(jodaDate("dd/MM/yyyy")),
"completion" -> optional(jodaDate("dd/MM/yyyy")),
"expectedMoveIn" -> optional(jodaDate("dd/MM/yyyy"))
)(RelocationDto.apply)(RelocationDto.unapply)
)
I would like to add validation so that if _type=="sale", then exchange is a required field, but if _type=="let" then expectedMoveIn is a required field. I cant seem to find a way to do this with the standard play validators, is there a way to do it?
Cheers
Nic
I used to work for Her Majesty's Revenue and Customs (UK) and looks like HMRC have open-sourced a very useful and easy to use library specialising in conditional Play mappings: https://github.com/hmrc/play-conditional-form-mapping
You can use the verifying method of Mapping. This will allow you to create constraints after the form has been successfully bound to a class, where you can access other fields. It accepts the error message and a boolean function, which will add an error to the form when false.
val relocationDtoForm: Form[RelocationDto] = Form(
mapping(
"_type" -> text,
"sourceToken" -> text,
"exchange" -> optional(jodaDate("dd/MM/yyyy")),
"completion" -> optional(jodaDate("dd/MM/yyyy")),
"expectedMoveIn" -> optional(jodaDate("dd/MM/yyyy"))
)(RelocationDto.apply)(RelocationDto.unapply)
.verifying(
"Exchange is required for sales.",
relocationRto => if(relocationRto._type == "sale") relocationRto.isDefined else true
).verifying(
"Expected move in is required for let?",
relocationRto => if(relocationRto._type == "let") expectedMoveIn.isDefined else true
)
)
My final solution at long last was:
def save(id: String) = Action { implicit request =>
//Runs some extra validation based on the _type value
def typeSpecificValidate(params: Map[String,Seq[String]]): Seq[FormError] = params("_type") match {
case Seq("sale") => {
Forms.tuple(
"exchange" -> jodaDate("dd/MM/yyyy"),
"completion" -> jodaDate("dd/MM/yyyy")
).bind(params.mapValues(seq => seq.head)) match {
case Left(errors) => errors //Bind returns a Left(List(FormErrors)) or a Right(boundTuple)
case _ => Nil
}
}
case Seq("let") => {
Forms.tuple(
"expectedMoveIn" -> jodaDate("dd/MM/yyyy")
).bind(params.mapValues(seq => seq.head)) match {
case Left(errors) => errors //Bind returns a Left(List(FormErrors)) or a Right(boundTuple)
case _ => Nil
}
}
}
val extraErrors = typeSpecificValidate(request.body.asFormUrlEncoded.get)
Logger.debug("Custom validator found: " + extraErrors)
val ff = relocationDtoForm.bindFromRequest
ff.copy(errors = ff.errors ++ extraErrors).fold(
formWithErrors => {
formWithErrors.errors.foreach(e => Logger.debug(e.toString))
BadRequest(views.html.relocations.detail(id, formWithErrors))
},
relocationDto => {
Logger.debug(relocationDto.toString)
Ok(views.html.relocations.detail(id, relocationDtoForm.fill(relocationDto)))
}
)
}

Ckeditor plugin - validating a text field

I am creating plugin
I have this piece of code below:
What i am trying to do is make sure the email address they enter is valid.
Just not sure how to stop the onOK if the email address is not valid.
Thanks
This is a code snippet of the plugin
contents : [
{
id : 'info',
label : editor.lang.form.title,
title : editor.lang.form.title,
elements : [
{
id : 'destEmail',
type : 'text',
label : 'Email form results to:',
'default' : 'randy#me.com',
required : true,
accessKey : 'T',
commit : function( element )
{
var emailRegEx = /^[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,4}$/i;
if (this.getValue().search(emailRegEx) == -1) {
alert("Please enter a valid email address.");
return false;
}
element.setAttribute('id', this.getValue() );
}
}
]
}
]
Please take a look on official sample and validate property. You can write your own validation method at this point.
You can also use one of the available (still not documented in API). You probably want to do something like this (CKEditor 4):
...
validate: CKEDITOR.dialog.validate.regex( /^[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,4}$/i, "Please enter a valid email address." );
...
It is also possible to combine existing validators and/or write custom validators:
function customValidator( x, msg ) {
return function() {
var value = this.getValue(),
pass = !!( CKEDITOR.dialog.validate.integer()( value ) && value < x );
if ( !pass ) {
return msg;
}
};
}
...
validate: customValidator( 5, 'Error message when larger than 5.' )
...

Resources