2
votes

I am trying to create an ActionBuilder which checks if the user is loggedin and if so, add the user object to the request(AuthenticatedRequest). With MySQL this would be easy because resolving the user would not get a Future object. But in this particular case, we use MongoDB with ReactiveMongo for Play, which does return a future value.

I have made this little snippet here so far. But it gets me a type mismatch:

type mismatch; found : scala.concurrent.Future[Option[models.User]] => scala.concurrent.Future[Object] required: Object => ?

object Authenticated extends ActionBuilder[AuthenticatedRequest] {


def invokeBlock[A](request: Request[A], block: (Request[A]) => Future[SimpleResult]) = {
    import models.User
    (for{
      sID <- request.session.get("sessionID")
      code <- request.session.get("otherCode")
      user: Future[Option[User]] <- models.Session.getUserBySessionAndCode(sID, code)
    } yield {
      (for{
        uAbs <- user
      } yield {
        if(uAbs.isDefined) {
          block(AuthenticatedRequest(uAbs.get, request))
        }else{
          BadRequest
        }
      })
    }).getOrElse(Future.successful(BadRequest))
  }
}

Do you have any idea how to move on from here? Maybe this is even the wrong approach. Thanks!

1

1 Answers

1
votes

How about separating the steps into smaller chunks and explicitly typing them the way you expect the types should be, this way it will be clearer and you will find out where your idea and what you have written goes in different directions, for example:

def userFromRequest(request: Request): Future[Option[User]] = 
  for{
    sID <- request.session.get("sessionID")
    code <- request.session.get("otherCode")
    maybeUser <- models.Session.getUserBySessionAndCode(sID, code)
  } yield maybeUser

def invokeBlock[A](request: Request[A], block: (Request[A]) => Future[SimpleResult]) = {
  userFromRequest(request).flatMap {
    case None => Future.successful(BadRequest)
    case Some(user) => block(AuthenticatedRequest(user, request))
  }
}