Simple code that should check user by pass, user is active and after that update last login datetime.
def authenticate() = Action.async { implicit request =>
loginForm.bindFromRequest.fold(
errors => Future.successful(BadRequest(views.html.logon(errors))),
usersData =>{
val cursor = this.collection.find(BSONDocument("name" -> usersData._1)).one[Account].map(_.filter(p=>p.password == hashedPass(usersData._2, usersData._1)))
cursor.flatMap(p => p match {
case None => Future.successful(BadRequest(views.html.logon(loginForm.withGlobalError("user/pass incorect!!!"))))
case Some(user) => {
if(!user.active)
Future.successful(BadRequest(views.html.logon(loginForm.withGlobalError("inactive!!!"))))
else collection.update(BSONDocument("_id" -> user.id),
BSONDocument("$set" ->
BSONDocument("lastLogin" -> BSONDateTime(new org.joda.time.DateTime().getMillis()))))
.flatMap(x => gotoLoginSucceeded(user.id.stringify))
}
})
})
}
How to rewrite it to less flatMap/map spaghetti?
Another solution
def authenticate() = AsyncStack { implicit request =>
loginForm.bindFromRequest.fold(
errors => Future.successful(BadRequest(views.html.logon(errors))),
usersData =>{
for{
user <- this.collection.find(BSONDocument("name" -> usersData._1)).one[Account].map(_.filter(p=>p.password == hashedPass(usersData._2, usersData._1)))
update <- {
lazy val update = collection.update(BSONDocument("_id" -> user.get.id),
BSONDocument("$set" ->
BSONDocument("lastLogin" -> BSONDateTime(new org.joda.time.DateTime().getMillis()))))
update
}
result <- {
lazy val result = gotoLoginSucceeded(user.get.id.stringify)
result
}
} yield
if(user.isEmpty) BadRequest(views.html.logon(loginForm.withGlobalError("login\pass mismatch")))
else if(!user.get.active) BadRequest(views.html.logon(loginForm.withGlobalError("inactive")))
else if(update.err.isEmpty) result
else InternalServerError(views.html.logon(loginForm.withGlobalError("server error")))
})
}
I would probably refactor the code into something like this:
I prefer doing password & user validation in the form validation clauses -- would be something like this (untested, but you get the idea):
And then the controller becomes much simpler: