Different model validation on User Name in Scala P

2019-03-22 07:47发布

I have user mapping as follows (there are few others too)

val userMapping: Mapping[User] = mapping(
    "id" -> ignored(NotAssigned: Pk[Long]),
    "title" -> nonEmptyText,
    "name" -> nonEmptyText,
    "userName" -> nonEmptyText,
    "skype" -> nonEmptyText,
    "emailId" -> ignored("": String),
    "secondaryEmailId" -> ignored("": String),
    "password" -> ignored("": String),
    "position" -> optional(text),
    "active" -> boolean,
    "subscribeEmail" -> boolean,
    "creationDate" -> optional(date("yyyy-MM-dd")),
    "lastUpdatedDate" -> optional(date("yyyy-MM-dd"))
  )(User.apply)(User.unapply)

The problem is if I apply validation on userName as

"userName" -> nonEmptyText.verifying("User name is already taken", user => !User.findUserByUserName(user.userName).isDefined)

this works perfectly fine on user creation but on edit form this validation breaks. I want to re use the same mapping for both create and update.

Currently I have moved it from form field to form level but thing is until all the form level error goes this validation is never reached and shown.

My complete form mapping is as follows (Same problem with company name).

val registerForm:Form[(User,Company)] = Form(
    mapping(
      "user" -> userMapping.verifying("User name is already taken", user => !User.findUserByUserName(user.userName).isDefined),
      "password" -> passwordMapping,
      "company" -> companyMapping.verifying("Company name is already registered", company => !Company.findCompanyByCompanyName(company.name).isDefined),
      "emailPair" -> emailPairMapping
    ){(user,passwords,company,emailPair) => (user.copy(password = passwords._1,emailId = emailPair._1,secondaryEmailId = emailPair._2,active = true),company)} //binding apply
     {userCompanyTuple => Some(userCompanyTuple._1, ("",""),userCompanyTuple._2,(userCompanyTuple._1.emailId,userCompanyTuple._1.secondaryEmailId))} //un binding un apply

  )

For edit case I am having mapping as (validation still to be applied)

val registerFormEdit:Form[(User,Company)] = Form(
    mapping(
      "user" -> userMapping,
      "company" -> companyMapping,
      "emailPair" -> emailPairMapping
    ){(user,company,emailPair) => (user.copy(emailId = emailPair._1,secondaryEmailId = emailPair._2,active = true),company)} //binding apply
    {userCompanyTuple => Some(userCompanyTuple._1,userCompanyTuple._2,(userCompanyTuple._1.emailId,userCompanyTuple._1.secondaryEmailId))} //un binding un apply

  )

Another challenge I see is how to get hold of id in edit validation as "id" is ignored. Will I have to handle the edit case in update action method?

In case I'll have to do it in update action method sample snippet would be great as I am also confused how to add error messages in action method.

Would be really great if someone provides input how this can be accomplished.

I using Scala with Play! 2.

Thanks.

1条回答
该账号已被封号
2楼-- · 2019-03-22 08:43

For validating the uniqueness of the userName and company, I believe the problem is that on editing the User, the validator function finds the userName / company in the Database because it is the record you inserted beforehand. So you will need to check if the userName / company exists and if it does exist, check if the id of the row is the id of the user. If they are the same, return true because it has only found the record you're currently updating.

With the id of the User, it's best to handle this in the Action and not the form binding due to security implications. E.g if the id is set and submitted in the form, it would be easy for someone to change the value of the id input to the id of another User to change their details. This is similar to how GitHub got compromised last year http://www.infoq.com/news/2012/03/GitHub-Compromised

In terms of a rough code snippet, something along the lines of:

def update(userId: Long) = Action { implicit request =>
  val user = User.find(userId)
  // Some type of authorization
  if(!authorize(getCurrentUser(), user) {
    BadRequest("access denied")
  } else {
    UserFormWithMappings.bindFromRequest().fold(
       formWithErrors => Ok("form errors"),
       updatedUser  => {
         updatedUser.id = userId
         User.update(updatedUser) // insert into db
         Ok("User changes saved")
       }
    )
  }
}
查看更多
登录 后发表回答