Scala Type Mismatch - scala

I am having a problem with type mismatch.
type mismatch; found : Option[models.User] required: models.User
def authenticate = Action { implicit request =>
signinForm.bindFromRequest.fold(
formWithErrors => BadRequest(html.signin(formWithErrors)),
user => Redirect(routes.Application.active).withSession(Security.username -> User.getUserName(user))
)
}
How can I force the function to accept Option[models.User] or can I convert the models.User into an Option?
The error occurs here: User.getUserName(user). getUserName requires models.User types.
===============================================
Update with all code used:
From User.scala
def authenticate(email: String, password: String) : Option[User] = {
(findByEmail(email)).filter { (user => BCrypt.checkpw(password, user.password)) }
}
def findByEmail(email: String) : Option[User] = {
UserDAO.findOne(MongoDBObject("email" -> email))
}
From Application.scala
val signinForm = Form {
mapping(
"email" -> nonEmptyText,
"password" -> text)(User.authenticate)(_.map(user => (user.email, "")))
.verifying("Invalid email or password", result => result.isDefined)
}
def authenticate = Action { implicit request =>
signinForm.bindFromRequest.fold(
formWithErrors => BadRequest(html.signin(formWithErrors)),
user => Redirect(routes.Application.active).withSession(Security.username -> User.getUserName(user.get))
)
}

To de-option an Option[User] into a User, you can do one of the following:
1) The unsafe way. Only do this if you are sure that optUser is not None.
val optUser: Option[User] = ...
val user: User = optUser.get
2) The safe way
val optUser: Option[User] = ...
optUser match {
case Some(user) => // do something with user
case None => // do something to handle the absent user
}
3) The monadic safe way
val optUser: Option[User] = ...
optUser.map(user => doSomething(user))
The biggest thing is that, if it's possible that optUser might actually be None, you need to figure out what you actually want to happen in the case that there is no User object.
There's a lot more information about Option in other StackOverflow questions if you'd like to read more.

Related

how to apply Form validators on object

I have an API in Scala. When I want to create a new User, i need validators on some fields (UserName, FirstName, LastName). I can't find a solution to apply the Form on my case class User. I thought using (User.apply) this will override automatically my User class, but this isn't happening.
User.scala
case class User(
id: Int = 0,
userName: String,
firstName: String,
lastName: String
)
object User {
import play.api.libs.json._
implicit val jsonWrites = Json.writes[User]
implicit val userReads = Json.reads[User]
def tupled = (User.apply _).tupled
}
// Form validator for post requests
object UserForm {
val form: Form[User] = Form(
mapping(
"id" -> number,
"userName" -> text(minLength = 5),
"firstName" -> text(minLength = 5),
"lastName" -> nonEmptyText
)(User.apply)(User.unapply)
)
}
UsersController.scala
def create = Action(parse.json) { implicit request => {
val userFromJson = Json.fromJson[User](request.body)
userFromJson match {
case JsSuccess(user: User, path: JsPath) => {
var createdUser = Await.result(usersRepository.create(user), Duration.Inf)
Ok(Json.toJson(createdUser))
}
case error # JsError(_) => {
println(error)
InternalServerError(Json.toJson("Can not create user"))
}
}
}
}
UsersRepository.scala
def create(user: User): Future[User] = {
val insertQuery = dbUsers returning dbUsers.map(_.id) into ((x, id) => x.copy(id = id))
val query = insertQuery += user
db.run(query)
}
(UsersRepository doesn't matter so much in this problem)
So, when I read the json, I think there need to apply the form validators
val userFromJson = Json.fromJson[User](request.body)
but nothing happening. Another problem is if I send from client a null parameter, will get an error, can not read and create an User.
For example :
"firstName": "" - empty userName will pass
"firstName": null - will fail
This depends on how is configured the User class in client (Angular), with the field null or empty in constructor. I prefer to set it null, even if is a string, if is not a required field (better NULL value in database, than an empty cell)
Try to use this:
request.body.validate[User]
One other thing, you shouldn't use
var createdUser = Await.result(usersRepository.create(user), Duration.Inf)
So use val´s over var´s and the other thing, you don't need to force the future to resolve, use it like this:
val createdUser = usersRepository.create(user)
createdUser.map(Ok(Json.toJson(_)))
And your action should be async.
Find a solution, my Form need to be part of object User, and not to be another object.
object User {
import play.api.libs.json._
implicit val jsonWrites = Json.writes[User]
implicit val userReads = Json.reads[User]
val form: Form[User] = Form(
mapping(
"id" -> number,
"userName" -> text(minLength = 2),
"firstName" -> text(minLength = 4),
"lastName" -> nonEmptyText
)(User.apply)(User.unapply)
)
def tupled = (User.apply _).tupled
}
and the method in Controller became :
def create = Action(parse.json) { implicit request => {
User.form.bindFromRequest.fold(
formWithErrors => BadRequest(Json.toJson("Some form fields are not validated.")),
success => {
val userFromJson = Json.fromJson[User](request.body)
userFromJson match {
case JsSuccess(user: User, path: JsPath) => {
val createdUser = Await.result(usersRepository.create(user), Duration.Inf)
Ok(Json.toJson(createdUser))
}
case error#JsError(_) => {
println(error)
InternalServerError(Json.toJson("Can not create user"))
}
}
}
)
}
}
I know, I need to format my code ... using IntelliJ is so annoying after Visual Studio :(

Function with Future return type always returns None

I have the following functions:
//retrieves record from database
def getAll: Future[List[User]] = {
try {
Logger.info("Getting all user record.")
db.run(userTableQuery.to[List].result)
}
catch {
case ex: Exception => Logger.error("Exception in getting all user record. " + ex)
Future {
List[User]()
}
}
}
//checks whethe the email exist in list or not
def checkEmail(email : String): Future[Option[User]] ={
/* userRepo.getAll.map(userList => userList.filter(user => user.email == email).map { value => println(value)
userList
})*/
userRepo.getAll.map(userList => userList.filter(user => user.email == email).headOption)
}
//allows to sign in and redirects to dashboard
def signIn() = {
Logger.debug("signingIn in progress. ")
loginForm.bindFromRequest.fold(
formWithErrors => {
Logger.error("Sign-In badRequest.")
Future(BadRequest(views.html.home(webJarAssets, formWithErrors, signUpForm)))
},
validData => {
userService.checkEmail(validData.email).map(value => {
value match {
case Some(us) =>Redirect(routes.HomeController.homePage).flashing("ERROR" -> "User exist")
case None => Redirect(routes.HomeController.homePage).flashing("ERROR" -> "User doesn't exist")
}
}
)
}
)
}
But when I call signin() it always returns None.
I used some debugger code and I guess filter() inside checkMail() is not working properly.
However getall() working properly and gives all the record in database.
I think the problem is in how you compare the user email with the provided one inside the filter in the checkMail() function.
Strings equality is a bit tricky, if you compare them using == you are comparing the objects and not the values so you should use .equals() to compare the values.
You can read more on this blog post
Try to rewrite checkMail() like this:
def checkEmail(email : String): Future[Option[User]] ={
userRepo.getAll.map(userList => userList.filter(user => user.email.equals( email ) ).headOption)
}
You can also simplify .filter() e .headOption using find(), it does the same thing only in one command. You can rewrite it like this:
def checkEmail(email : String): Future[Option[User]] ={
userRepo.getAll.map(userList => userList.find(user => user.email.equals( email ) ) )
}
Instead of using filter you may use find method under checkmail. And also, since this is scala you are using "==" correctly, please see blog here
I hope this code would fix:
//checks whethe the email exist in list or not
def checkEmail(email : String): Future[Option[User]] ={
/* userRepo.getAll.map(userList => userList.filter(user => user.email == email).map { value => println(value)
userList
})*/
userRepo.getAll.map(userList => userList.find(user => user.email == email))
}
I tried to simulate/experiment regarding your implementation in direct way using the terminal:
scala> case class User(email: String)
defined class User
scala> import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.ExecutionContext.Implicits.global
scala> val allUser = scala.concurrent.Future {List(User("carl#test.com"), User("los#test.com"), User("pos#test.com"))}
allUser: scala.concurrent.Future[List[User]] = scala.concurrent.impl.Promise$DefaultPromise#751d3241
scala> val checkmail = allUser.map(userlist=>userlist.find(user=>user.email == "carl#test.com"))
checkmail: scala.concurrent.Future[Option[User]] = scala.concurrent.impl.Promise$DefaultPromise#1358b28e
scala> val rslt = checkmail.map(value => value match {case Some(x) =>println(x); x.email case None => println("None"); "nothing" })
rslt: scala.concurrent.Future[Unit] = scala.concurrent.impl.Promise$DefaultPromise#18324f97
User(carl#test.com)
scala> import scala.concurrent.duration._
import scala.concurrent.duration._
scala> import scala.concurrent._
import scala.concurrent._
scala> Await.result(rslt, 3 seconds)
warning: there was one feature warning; re-run with -feature for details
res8: String = carl#test.com

ReactiveMongo Scala DAO pattern

I have the following DAO, Service Object and Controller pattern in my Playframework project:
CredentialsDAO.scala:
def find(authType: AuthType.Value, authAccountId: String) =
collection.find(
Json.obj(Fields.AuthType → authType,
Fields.AuthAccountId → authAccountId)).one[Credentials].recover(wrapLastError)
CredentialsService.scala:
def checkEmailPassword(email: String, password: String) = credentialsDAO.find(AuthType.EmailPassword, email).map(_.get) //Needs review
In my controller:
def auth = Action.async(parse.json) { request =>
{
val authRequest = request.body.validate[AuthRequest]
authRequest.fold(
errors => Future(BadRequest),
auth => {
//First verify username and password
val authRequestResult = for {
validCredential <- credentialsManager.checkEmailPassword(auth.email, auth.password)
validPassword <- BCrypt.checkFuture(auth.password, validCredential.passwordHash)
validAccount <- accountManager.getAccount(validCredential)
session <- sessionManager.createSession(validAccount.id, validAccount.roles)
touchedSession <- sessionManager.touchSession(session.id)
} yield AuthResponse(session.id, session.token, validAccount.id, validAccount.roles)
authRequestResult map {
case res: AuthResponse => Ok(Json.toJson(res))
case _ => NotFound
}
})
}
}
Question: Is this 'pattern' okay from a functional programming perspective? In particular, I'm bothered by this line in CredentialsService.scala:
def checkEmailPassword(email: String, password: String) = credentialsDAO.find(AuthType.EmailPassword, email).map(_.get) //Needs review
I'm new to Scala but I think there are better ways of dealing with _.get in the line above? Any suggestions/ideas would be highly appreciated.
Thanks in advance.

Scala: type mismatch; found : scala.concurrent.Future[Option[models.Account]] required: Option[?]

Give then following code:
AccountsDAO.scala:
def find(id: EntityId): Future[Option[Account]] =
collection.find(Json.obj(Fields.Id -> id)).one[Account]
And AccountService.scala:
def getAccount(id: Option[Credentials]) = id.flatMap {
accountId => accountDAO.find(accountId.accountId) //Throws an error
}
The commented line above throws this error:
type mismatch; found : scala.concurrent.Future[Option[models.Account]] required: Option[?]
What am I missing? Why does flattop return an Option[?]. If I change the return type of the getAccount method as:
def getAccount(id: Option[Credentials]): Future[Option[Account]] = id.flatMap {
accountId => accountDAO.find(accountId.accountId) //Still throws an error
}
I get the error below:
type mismatch; found : Option[Nothing] required: scala.concurrent.Future[Option[models.Account]]
What is going on? What am I missing?
Thanks in advance.
Edit : Here's the code in the controller and what I'm trying to do:
def auth = Action.async(parse.json) { request =>
{
val authRequest = request.body.validate[AuthRequest]
authRequest.fold(
errors => Future(BadRequest),
auth => {
//First verify username and password
val authRequestResult = for {
validCredentials <- credentialsManager.checkEmailPassword(auth.email, auth.password)
account:Option[Account] <- accountManager.getAccount(validCredentials)
session:Session <- sessionManager.createSession(account.get.id, account.get.roles)
touchedSession <- sessionManager.TouchSession(session.id)
} yield AuthResponse(session.id, session.token, account.get.id, account.get.roles)
authRequestResult map {
case res: AuthResponse => Ok(Json.toJson(res))
case _ => NotFound
}
})
}
}
The checkEmailPassword method above returns a Future[Option]:
def checkEmailPassword(email: String, password: String) =
for {
credentials <- credentialsDAO.find(AuthType.EmailPassword, email)
validPassword <- BCrypt.checkFuture(password, credentials)
} yield (credentials)
And credentialsDAO.find:
def find(authType: AuthType.Value, authAccountId: String) =
collection.find(
Json.obj(Fields.AuthType → authType,
Fields.AuthAccountId → authAccountId)).one[Credentials].recover(wrapLastError)
So when checkEmailPassword returns an Option[Credentials] object, is it okay to assume the for comprehension in the controller will not execute any further if it returns a None? Then I could just say something like account:Option[Account] <- accountManager.getAccount(validCredentials.get.id). Is there a better way to structure/organize this code? Any patterns that I can follow/use?

Play Framework:Error type mismatch; found :Int required: play.api.mvc.Result

I am trying to save form values to a database, and play I am getting the error:
type mismatch; found :Int required: play.api.mvc.Result
And here is my code :
Application.scala
import play.api._
import play.api.mvc._
import play.api.data._
import play.api.data.Forms._
import views.html.defaultpages.badRequest
import play.api.data.validation.Constraints._
import models.User
import models.UserData
object Application extends Controller {
val RegisterForm = Form(
mapping(
"fname" -> nonEmptyText(1, 20),
"lname" -> nonEmptyText(1, 20),
"email" -> email,
"userName" -> nonEmptyText(1, 20),
"password" -> nonEmptyText(1, 20),
"age" -> number,
"choice" -> text,
"gender" -> text
)(User.apply)(User.unapply)
.verifying("Ag should be greater then or equal to 18", model => model.age match {
case (age) => age >= 18
})
)
def index = Action {
Ok(views.html.index(RegisterForm))
}
def register = Action { implicit request =>
RegisterForm.bindFromRequest().fold(
hasErrors => BadRequest(views.html.index(hasErrors)),
success => {
User.save(success)
}
)
}
}
User.scala
import anorm._
import play.api.db.DB
import anorm.SqlParser._
import play.api.Play.current
case class User (
fname: String,
lname: String,
email: String,
userName: String,
password: String,
age: Int,
choice: String,
gender: String
)
object User {
val userinfo = {
get[String]("fname") ~
get[String]("lname") ~
get[String]("email") ~
get[String]("userName") ~
get[String]("password") ~
get[Int]("age") ~
get[String]("choice") ~
get[String]("gender") map {
case fname~lname~email~userName~password~age~choice~gender =>
User(fname, lname, email, userName, password, age, choice, gender)
}
}
def save(ud: User) = {
DB.withConnection { implicit c =>
SQL ("insert into userinfo(fname,lname,email,userName,password,age,choice,gender) values ({fname},{lname},{email},{userName},{password},{age},{choice},{gender})")
.on('fname -> ud.fname, 'lname ->ud.lname ,'email ->ud.email, 'userName->ud.userName , 'password->ud.password ,'age->ud.age, 'choice->ud.choice,'gender->ud.gender)
.executeUpdate()
}
}
}
i took help from the scala cook book for this save functions but i am having problem as i am new in play scala maybe the mistake was minor one so please help me,all i want is to store all the input values in DB which was entered in the form
The problem is with your controller function register:
def register = Action { implicit request =>
RegisterForm.bindFromRequest().fold(
hasErrors => BadRequest(views.html.index(hasErrors)),
success => {
// You need to return a `Result` here..
// Maybe redirect to login?
// Redirect("/login")
User.save(success)
}
)
}
The problem is that User.save returns an Int, and the controller function is expecting a Result, like Ok(..), Redirect(...), etc. You need to do something with the result of User.save to return a Result.
It would be better if you used executeInsert() instead of executeUpdate(), as executeInsert returns Option[Long] by default--which will help you determine if the save was successful.
e.g.:
def save(ud: User): Option[Long] = {
DB.withConnection {implicit c =>
SQL("insert into userinfo(fname,lname,email,userName,password,age,choice,gender) values ({fname},{lname},{email},{userName},{password},{age},{choice},{gender})")
.on('fname -> ud.fname, 'lname ->ud.lname ,'email ->ud.email, 'userName->ud.userName , 'password->ud.password ,'age->ud.age, 'choice->ud.choice,'gender->ud.gender)
.executeInsert()
}
}
Then within your controller function use it like this:
def register = Action { implicit request =>
RegisterForm.bindFromRequest().fold(
hasErrors => BadRequest(views.html.index(hasErrors)),
success => {
User.save(success) map { newId =>
Redirect("/login") // or whatever you want this to do on success
} getOrElse {
InternalServerError("Something has gone terribly wrong...")
}
}
)
}
You can replace my placeholder results with something a little more meaningful in your application.
The save(ud:User) method returns the integer value. Action should always return Result, so write
success => {
val result = User.save(success)
Ok(result.toString)
}